segunda-feira, 23 de novembro de 2009

TThread - Melhores práticas

Título alternativo: Três Pratos de Thread para Três Tigres Tristes

Aqui vai alguns conceitos sobre a classe TThread, que compartilho contigo:

Resume ou Start:

O método Resume coloca a thread para funcionar, ou seja, executa o método Execute.
No Delphi 2010 Resume está deprecated, sendo usado o Start.

Suspend:

O método Suspend suspende a thread do ponto em que estiver.

Terminate:

O método Terminate seta a proriedade Terminaded para True, apenas isso... Dentro do Execute é que está o segredo...

WaitFor:

A função WaitFor é que efetivamente aguarda o término da thread. Mas cuidado! Para que funcione corretamente temos que tomar três cuidados, do contrário você esperará eternamente...

Terminated

No Execute, tome cuidado com a variável Terminated, sempre vericando em pontos estratégicos. O exemplo básico é o que segue abaixo... Friso: EXEMPLO BÁSICO:

procedure TMinhaThread.Execute;
begin
try
while not (Self.Terminated) do
begin
Sleep(10);
Application.ProcessMessages;
{...}
{...}

//Ponto estratégico para verificação...
if (Self.Terminated) then
Abort;

{...}
{...}
end;
except
on E: Exception do
begin
{...}
end;
end;
end;


Evento OnTerminate

Você deve setar o evento OnTerminate, senão o WaitFor não retorna...

Cuidado com a thread suspensa!

Se a thread estiver suspensa, o WaitFor também não retorna. O código mais correto para terminar uma thread é o que segue abaixo:

procedure TForm1.Button3Click(Sender: TObject);
var
cRet : Cardinal;
begin
//Manda Terminar....
Self.FThread.Terminate;
//Verifica se a thread não esta suspensa...
if not (Self.FThread.Suspended) then
begin
//Aguarda o término da Thread 
cRet := Self.FThread.WaitFor;
Log(Format('Retornou: [%d]',[cRet]));
end else
begin
Log('Esta suspenso');
end;
//Livra a instância...
Self.FThread.Free;
Self.FThread := nil;
end;


ReturnValue

A função WaitFor retorna um valor Integer... e da onde vem este valor? Da propriedade ReturnValue, que poderá ser setada no Execute.

Abort

Abort, como sabido, gera uma exceção do tipo EAbort, e na minha opnião é a maneira mais apropriada de terminar a execução de um Execute. Veja no trecho de código acima.

Syncronize

Syncronize executa um método pela thread principal. Na minha opnião só é válido em aplicativos GUI (com interface gráfica). Fora desta situação, dê preferência para TCriticalSection.

Por ora é isso. Existem outros aspectos mas acho esse os mais importantes.

Aproveito para compartilhar um PDF que a anos me ajuda a enfrentar as treads:

http://docs.google.com/fileview?id=0B2-0qFgCBKnjNmJhZjg2NDktYjIyOS00ODA0LTk0MjgtZGFhZDJiYzhkODJm&hl=pt_BR

Uma outra leitura interessante sobre o assunto:

http://balaiotecnologico.blogspot.com/search?q=thread

Minha lista de blogs