Voltar
Por que eu devo ler este artigo:Neste artigo aprenderemos como utilizar threads em Delphi. Veremos alguns dos conceitos teóricos suficientes para aplicar de forma adequada esse recurso pouco utilizado no desenvolvimento diário.

Apresentamos um problema simples, abordando nele situações reais como, por onde começar, como cancelar uma thread, como impedir que um sistema seja fechado se suas threads ainda estão em execução para posteriormente abordar seu uso em conjunto com banco de dados.

Será utilizada a classe TThread, disponível antes mesmo do Delphi 7, porém os exemplos são construídos utilizando Delphi XE 6.

Para podermos fazer uso efetivo de threads e da programação multithread em si, é preciso compreender primeiramente o que é: processo, módulo e thread.

  • Processo: Podemos dizer de forma simplista que um processo é um programa que é executado em uma máquina, compartilhando seu processamento e memória. Partindo para uma definição mais técnica, sabemos que um processo executa um bloco de comandos, e esse processo o executa de forma isolada.

    Os recursos como memória, disco e processamento utilizados são virtualizados de tal forma que cada processo possui seu próprio conjunto de recursos, que não é acessível a outros processos.

  • Módulo: Os processos executam módulos. Esses podem ser totalmente diferentes, por exemplo, um mesmo processo pode executar um código de envio de e-mail enquanto que outro pode executar um download de página Web.

    Toda a execução desses módulos acontece de forma simultânea. Por exemplo, ao pensarmos no sistema operacional Windows, o mesmo não deixa de realizar uma operação de I/O (código de arquivos) enquanto você imprime um documento no Word.

  • Thread: As threads foram desenvolvidas quando ficou claro que o tempo de processamento poderia ser melhor utilizado. Em outras palavras, quando se desejava que um sistema executasse várias ações, de forma simultânea. Um bom exemplo desse tipo de ação é a verificação de grafia enquanto está se digitando um texto.

    O processo de entrada não é parado esperando pelo processo de correção. Os dois são executados simultaneamente. Hoje é muito comum máquinas com mais de um núcleo de processamento, porém sem dúvida alguma o número desses processadores físicos é menor que o número de threads que podem rodar em paralelo.

    Para contornar isso, os sistemas operacionais oferecem suporte ao time slicing. O time slicing nada mais é do que o controle de execução das threads, onde cada uma é executada por um curto período e essa execução é alternada como em um rodízio. Isso permite que um único processador execute várias threads.

Quando as threads são úteis?

As threads são úteis quando um aplicativo necessita realizar uma operação longa. Mas como identificar esse processamento? Vamos imaginar que um sistema efetua uma consulta de clientes e no momento da pesquisa o usuário desse sistema começa a redigir um e-mail, enquanto o sistema continua efetuando a pesquisa... porém agora a janela desse sistema avisa que o “sistema parou de responder”.

O usuário leigo vai simplesmente pensar que o sistema travou e irá fechá-lo. Porém, como programadores, sabemos que o sistema em si não estava travado.

A consulta poderia estar muito bem sendo realizada, contudo, devido ao longo e pesado processamento, o processo principal do sistema não pôde mais responder às mensagens do sistema operacional e assim, o sistema operacional acha que o sistema está congelado.

Colocar esse processamento pesado encapsulado em uma thread faria com que o sistema, que roda sob um processo principal, continuasse respondendo ao sistema operacional. Ou seja, uma thread não altera o propósito de um sistema, ela simplesmente muda o tempo de execução das operações, tornando-se uma solução elegante para esse tipo de situação.

Outra situação onde o uso de thread é útil é quando temos disponível um ambiente multiprocessado, que como já foi dito, é muito comum. Assim, podemos fazer com que um aplicativo desenvolvido por nós, possa fazer uso eficiente de mais de um núcleo de processamento. O uso consciente das threads pode fazer com que esse sistema, que algumas vezes parece que está lento, se torne mais responsivo.

Entendendo como um programa funciona

Para facilitar o entendimento sobre threads, vamos imaginar um programa VCL bem simples. A Figura 1 mostra o funcionamento de um formulário principal com um único botão que ao ser clicado executa uma chamada ao comando ShowMessage.

Processamento de
uma aplicação simples
Figura 1. Processamento de uma aplicação simples

No ponto A o programa é iniciado e até chegar no ponto B, a thread do aplicativo – que é a thread VCL – espera por mensagens do sistema operacional. Se se nada é recebido ou enviado, até chegar no ponto C a thread é então suspensa.

No ponto C é onde o usuário clica no botão, que leva a execução ao ponto D, onde a mensagem é exibida. Uma vez exibida chegamos no ponto E, onde o aplicativo aguarda pelo “OK” na tela. Enquanto não se pressiona o OK, a thread fica em suspensão. Ao clicar no OK (ponto F) a mensagem é fechada e a thread entra novamente em suspensão até o usuário finalizar o aplicativo no ponto G.

Alguns pontos dessa visualização precisam ser destacados. Um deles é que a thread não é mantida em execução continuadamente.

Existem períodos onde ela não recebe estímulo externo e não está processando nada enquanto isso. Os recursos alocados pela aplicação estão lá, a janela é visível mas nenhum de seus códigos é executado.

Quando a aplicação é iniciada, a thread principal é iniciada criando a janela principal. Ao finalizar esse seu propósito, o código recai em uma parte da VCL que executa um loop contínuo que requisita ao sistema operacional por mais mensagens.

Se não há nada a ser processado, o próprio sistema operacional suspende a thread. Mas, quando o usuário clica no botão da janela, a thread é acordada novamente, recebendo a mensagem que houve o clique no botão.

Essa operação de suspensão e reativação acontece várias vezes.

Cálculo de número primos

Identificar se um número é primo ou não pode ser uma operação custosa de acordo com o tamanho do número a ser calculado.

Essa é uma operação que pode ser executada em uma Thread, liberando a thread principal para outras atividades. O Delphi encapsula uma thread através da classe TThread, que traz em sua implementação várias peculiaridades já resolvidas.

Para experim ...

Quer ler esse conteúdo completo? Tenha acesso completo