Clique para saber mais...
  Home     Download     Produtos / Cursos     Revista     Vídeo Aulas     Fórum     Contato   Clique aqui para logar | 14 de Janeiro de 2026
  Login

Codinome
Senha
Salvar informações

 Esqueci minha senha
 Novo Cadastro

  Usuários
54 Usuários Online

  Revista ActiveDelphi
 Assine Já!
 Edições
 Sobre a Revista

  Conteúdo
 Apostilas
 Artigos
 Componentes
 Dicas
 News
 Programas / Exemplos
 Vídeo Aulas

  Serviços
 Active News
 Fórum
 Produtos / Cursos

  Outros
 Colunistas
 Contato
 Top 10

  Publicidade

  [Artigos]  Threads no Delphi, por onde começar? – Parte I
Publicado por rboaro : Segunda, Fevereiro 18, 2013 - 08:06 GMT-3 (957 leituras)
Comentários 6 Comentários   Enviar esta notícia a um amigo Enviar para um amigo   Versão para Impressão Versão para impressão
Diego Garcia Thread é um termo conhecido por qualquer “informata” que se preze, mas para quem não se recorda, qualquer aplicação utiliza no minimo uma thread (a thread principal ou main thread) onde o fluxo do processamento é executado, nessas aplicações os comandos são executados um por vez de forma sequencial. Até ai nada demais, mas a coisa passa a ficar interessante quando usamos mais de uma thread em uma aplicação, fazendo com que seja possível executar processamentos de forma paralela. No dia a dia usamos as threads para gerenciar tarefas que precisam ser executadas paralelamente, melhorar desempenho de processamentos, etc. Mas não se iluda, usar threads é simples, mas requer alguns cuidados.

Deixando a teoria e o blablabla de lado, vamos ver um pouco sobre como funcionam as threads no Delphi.
Começaremos criando um exemplo bem básico, faremos um método que escreve de 1 a N linhas em um arquivo de texto tendo o intervalo de 1 milissegundo a cada linha escrita, o nome deste arquivo sempre será hora, minuto, segundo e milésimo de criação e o numero de linhas escritas, ex: 14-30-01-200_total_linhas_1500.txt. Inicialmente criaremos esse método da forma comum e depois passaremos para uma thread, assim conseguiremos realizar algumas comparações no resultado final. Para a execução comum, faremos dessa forma:
procedure escreverArquivoDeTexto(const dirArquivo: string;
linhasAImprimir: integer);
var
linhasArquivoTexto : TStringList;
I: Integer;
begin
linhasArquivoTexto := TStringList.Create;
try
for I := 1 to linhasAImprimir do
begin
linhasArquivoTexto.Add(format('Linha numero %d',[i]));
Sleep(1);
end;
linhasArquivoTexto.SaveToFile(Format('%s\%s_total_linhas_%d.txt',[dirArquivo,FormatDateTime('hh-mm-ss-zzz',Now),linhasAImprimir]));
finally
linhasArquivoTexto.Free;
end;
end;

Para testar esse método, faremos com que ele seja executado 3 vezes e analisaremos a diferença de tempo de gravação entre um e outro, lembrando que, como ainda não estamos trabalhando com threads, será escrito um arquivo por vez.
escreverArquivoDeTexto(ExtractFileDir(ParamStr(0)),10500);
escreverArquivoDeTexto(ExtractFileDir(ParamStr(0)),10200);
escreverArquivoDeTexto(ExtractFileDir(ParamStr(0)),10400);

Usei um numero grande de linhas para que fosse possível medir o desempenho. Ao executar a sequencia acima, tive os seguintes arquivos criados no diretório do executável de teste:
14-47-22-711_total_linhas_10500.txt
14-47-33-078_total_linhas_10200.txt
14-47-43-661_total_linhas_10400.txt

Sendo assim, podemos concluir que levou cerca de 10 segundos de diferença para cada arquivo. Faremos agora novamente essa rotina, porém, faremos com que ela seja executada dentro de uma thread.
Para facilitar nossas vidas, o Delphi já possui o esqueleto padrão para a criação de uma thread, basta ir em FILE -> NEW -> OTHER -> THREAD OBJECT, após selecionar Thread Object será solicitado o nome da classe da sua Thread (para nosso exemplo utilizei TArquivoTextoInThread) e pronto, teremos o seguinte código já montado em uma nova unit:

type
TArquivoTextoInThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;

Antes de voltarmos a falar sobre conceitos, vamos primeiro preparar a nossa classe para que ela escreva em um arquivo de texto. Sendo rápido e prático, criaremos dois atributos privados na classe, um referente ao número de linhas a serem escritas e outro referente ao diretório onde o arquivo será criado. Feito isso, passaremos a nossa rotina de criar o arquivo de texto para dentro desta classe, ficando desta forma:

type
TArquivoTextoInThread = class(TThread)
private
FLinhasAImprimir : integer;
FDirArquivo : String;
procedure escreverArquivoDeTexto();
function gerarNomeArquivo():string;
protected
procedure Execute; override;
public
constructor Create (const CreateSuspended : boolean; const linhasAImprimir : integer; const dirArquivo : string);
end;

Certo, eu fiz algumas coisas a mais, mas vamos por partes, primeiro, vamos ver como ficou nosso método escreverArquivoDeTexto().

procedure TArquivoTextoInThread.escreverArquivoDeTexto;
var
linhasArquivoTexto : TStringList;
I: Integer;
begin
linhasArquivoTexto := TStringList.Create;
try
for I := 1 to Self.FLinhasAImprimir do
begin
linhasArquivoTexto.Add(format('Linha numero %d',[i]));
Sleep(1);
end;
linhasArquivoTexto.SaveToFile(Self.gerarNomeArquivo());
finally
linhasArquivoTexto.Free;
end;
end;

Basicamente nada mudou, só para melhorar a legibilidade do código foi criado um método para gerar o nome do arquivo de texto, porém ele tem a mesma lógica utilizada anteriormente:

function TArquivoTextoInThread.gerarNomeArquivo: string;
begin
result := Format('%s\%s_total_linhas_%d.txt',[Self.FDirArquivo,FormatDateTime('hh-mm-ss-zzz',Now),self.FLinhasAImprimir]);
end;

Sendo assim, até aqui nenhuma novidade, mas agora vamos para um pouco de conceitos analisando o construtor que fiz para a classe:

constructor TArquivoTextoInThread.Create(const CreateSuspended: boolean;
const linhasAImprimir: integer; const dirArquivo : string);
begin
Self.FLinhasAImprimir := linhasAImprimir;
Self.FDirArquivo := dirArquivo;
Self.FreeOnTerminate := true;
inherited Create(CreateSuspended);
end;

A classe TThread possui uma propriedade booleana chamada FreeOnTerminate que quando alterada para true a thread é liberada automaticamente da memória após a sua execução. Outra coisa que é importante de notar é o parâmetro CreateSuspended que o construtor da classe TThread recebe, ele basicamente define se a thread será criada suspensa ou não, ou seja, se a thread será executada automaticamente após a instância ser criada (CreateSuspended = false) ou se será necessário iniciar a execução da thread de forma manual (CreateSuspended = true) através do método Start. Para completar a implementação da nossa classe, vamos ver como ficou o método Execute() da thread:

procedure TArquivoTextoInThread.Execute;
begin
escreverArquivoDeTexto();
end;

Ok, imagino que você esperava mais do que simplesmente uma chamada para o método escreverArquivoDeTexto() porém, o segredo todo está ai, o método Execute() é exatamente o método que será executado assim que a thread for iniciada. Com isso, a nossa thread está pronta. Agora vamos fazer o mesmo teste que fizemos anteriormente mas dessa vez utilizando nossa thread:

var
oArquivoTextoInThread1 : TArquivoTextoInThread;
oArquivoTextoInThread2 : TArquivoTextoInThread;
oArquivoTextoInThread3 : TArquivoTextoInThread;
begin
oArquivoTextoInThread1 := TArquivoTextoInThread.Create(false,10500,ExtractFilePath(ParamStr(0)));
oArquivoTextoInThread2 := TArquivoTextoInThread.Create(false,10200,ExtractFilePath(ParamStr(0)));
oArquivoTextoInThread3 := TArquivoTextoInThread.Create(false,10400,ExtractFilePath(ParamStr(0)));
end;

Executando a rotina acima, como determinei que minha thread não irá iniciar suspensa, tive os seguintes arquivos criados no diretório do executável:

15-42-46-946_total_linhas_10200
15-42-47-167_total_linhas_10400
15-42-47-256_total_linhas_10500

Note que o último arquivo a ser criado foi o de 10500 linhas mesmo sendo o primeiro a ter sua rotina executada e outra coisa muito importante é a diferença de tempo na criação dos arquivos, se antes sem thread tivemos uma demora de 10 segundos para cada arquivo, aqui não passou de poucos milésimos, tivemos esse resultado pois cada arquivo demora cerca de 10 segundos para ser gerado, porém, como os 3 estavam sendo gerados ao mesmo tempo de forma paralela, não foi necessário utilizar uma fila de processamento.
Como o intuito deste post foi só demonstrar o uso de threads, não entrei em mais detalhes, porém, na próxima parte veremos um pouco mais sobre como controlar o ciclo de vida de uma thread.


Comentários Comentários
   Ordem:  
Comentários pertencem aos seus respectivos autores. Não somos responsáveis pelo seus conteúdos.


por: marcoantoneo (marco@pgm.com.br) : Fev 18, 2013 - 11:27
(Informações sobre o membro | Enviar uma mensagem)
Bom dia.
Francamente... Já tinha lido mta coisa sobre threads. Todos mto cansativos, usando logo de inicio mtas definições e expressões q para meu ver logo de inicio confundem mto o entendimento.
Com isso eu mesmo nunca utilizei tal artificio dentro da programação.
Acabei lendo o artigo por curiosidade e fiquei surpreso, pois, vi o quanto eh simples usar THREADS.
Parabens pela forma como o artigo foi desenvolvido e acho que eh por ae, iniciando com bons exemplos e ir desenvolvendo aos poucos o assunto. Estou ancioso aguardando por mais tópicos sobre o assunto.


por: ronaldospranger (ronaldospranger@gmail.com) : Fev 20, 2013 - 11:27
(Informações sobre o membro | Enviar uma mensagem) http://http://
Até ler este artigo, as threads eram um dragão da caverna para mim, agora ficou muito mais compreensível, estamos no aguardo das outras 3 partes!
Parabéns


por: marlonnardi (marlon.nardi@vanguardadobrasil.com.br) : Fev 23, 2013 - 03:52
(Informações sobre o membro | Enviar uma mensagem)
Parabéns pelo Artigo!

Após ler o artigo, já comecei a alterar algumas rotinas minhas para Thread...rsrs.

  Edição 112

Revista ActiveDelphi

  50 Programas Fontes


  Produtos

Conheça Nossos Produtos

Copyright© 2001-2016 – Active Delphi – Todos os direitos reservados