Threads! Threads! Threads!

Delphi

30/05/2005

Olá colegas.

Estou com o seguinte problema: tenho uma aplicação que executa uma série de passos seguidos, sendo que um dos passos no meio consiste em um gargalo de velocidade (é uma varredura no registro do Windows). Para melhorar o desempenho resolvi usar threads, dividindo cada hive do registro para uma thread. Assim uma thread vai varrer a HKEY_CLASSSES_ROOT, outra a HKEY_LOCAL_MACHINE, e assim sucessivamente, ao mesmo tempo. Só que é sabido que quando se lança uma thread o código é executado como em ´background´ em relação à linha de execução principal:

Step1;
Step2;
StepRegistry; // lança threads e passa para Step4
Step4;


Sendo que eu não desejo esse efeito assim. Eu quero executar código paralelo mas parar o código da aplicação até que todas as threads terminem. Vejam: no caso acima, StepRegistry lança as threads e [b:de28e92f43]imediatamente[/b:de28e92f43] Step4 é chamado. Ok. Só que eu não quero isso, eu quero que Step4 só entre quando todas as threads lançadas em StepRegistry terminarem, pois Step4 só pode ser executado quando StepRegistry terminar.

Resumindo eu quero um esquema assim (onde T1 é a linha principal e T2-T6, o processamento distribuído que quero fazer) ...

Em vez disso:

                  T2 ------------->
                  T3 ------------->
                  T4 ------------->
                  T5 ------------->
                  T6 ------------->
T1 -------|-------|--------------->

   Step1    Step2    StepRegistry (T2-T6)

                     Step4(T1)



Eu quero isso:

                  T2 ------------->
                  T3 ------------->
                  T4 ------------->
                  T5 ------------->
                  T6 ------------->
T1 -------|-------|               |----------->

   Step1    Step2    StepRegistry  Step4


Minha idéia inicial era parar a thread ´principal´ da aplicação. Mas não descobri como! Algo como Application.MainThread.Stop...

Agora o que tô pensando é em fazer o código que lança as threads ser o último da lista, ou seja, remover Step4. No código compartilhado pelas threads eu controlo quantas estão ativas e só executo Step4 após todas terminarem. Mas isso é meio gambiarrazinha. Tem um jeito, digamos, mais elegante?

Obrigado a todos!


Renatosilva

Renatosilva

Curtidas 0

Respostas

Massuda

Massuda

30/05/2005

Seu problema requer um mecanismo de sincronismo entre as threads. Me parece que você teria que criar um TEvent (da unit SyncObjs) para cada thread e fazer a thread principal do programa aguardar o TEvent de cada thread ser sinalizado. Sugiro dar uma olhada [url=http://www.pergolesi.demon.co.uk/prog/threads/ToC.html]nesta página[/url] (em inglês) para uma discussão sobre o assunto.


GOSTEI 0
Nildo

Nildo

30/05/2005

Olá renato!

Uma solução seria você pegar o handle da thread do form principal, pelo [b:7964ebdb69]GetCurrentThread[/b:7964ebdb69] (executando esse código no Form principal), e usar as APIs [b:7964ebdb69]SuspendThread[/b:7964ebdb69] e [b:7964ebdb69]ResumeThread[/b:7964ebdb69] passando como parâmetro o código da thread.

Mas cuidado ao mecher com isso para não cair em DeadLock.
Ou então, você poderia colocar no OnTerminate da StepRegistry para executar o Step4.

Ps.: Gostei do modo que você interpreta seus problemas :)


GOSTEI 0
Nildo

Nildo

30/05/2005

Seu problema requer um mecanismo de sincronismo entre as threads. Me parece que você teria que criar um TEvent (da unit SyncObjs) para cada thread e fazer a thread principal do programa aguardar o TEvent de cada thread ser sinalizado. Sugiro dar uma olhada [url=http://www.pergolesi.demon.co.uk/prog/threads/ToC.html]nesta página[/url] (em inglês) para uma discussão sobre o assunto.


Poderia criar um Handle qualquer e utilizar o WaitForSingleObject. Eu acho mais simples, mas eu acho que usando o OnTerminate fica mais facil para ele não cair em DeadLock


GOSTEI 0
Renatosilva

Renatosilva

30/05/2005

Valeu pessoal! Nildo, isso mesmo que eu queria, como parar a thread principal. Mas queria que me explicasse o que é deadlock (já estudei isso mas não entendo direito).

Quando mexer no programa dou um feedback do que consegui fazer. Obrigado!!!


GOSTEI 0
Nildo

Nildo

30/05/2005

Valeu pessoal! Nildo, isso mesmo que eu queria, como parar a thread principal. Mas queria que me explicasse o que é deadlock (já estudei isso mas não entendo direito). Quando mexer no programa dou um feedback do que consegui fazer. Obrigado!!!


Se você parar uma Thread que estava sincronizada com outra, que continua rodando, vai dar altos erros! hehehe

E você deve tomar cuidado pra não parar uma Thread que trata de resumir a execução de outras.

Resumidamente, você nao pode parar uma thread que é dependente de outras threads


GOSTEI 0
Beppe

Beppe

30/05/2005

Ou com semáforos.

´Sem´ é um campo no form do tipo THandle.

procedure TForm1.StepRegistry;
const
  NumThreads = 5;
var
  Falta: Integer;
begin
  Sem := CreateSemaphore(nil, 0, 1, ´´);
  try
    Falta := NumThreads;

    // crie seus threads aqui

    while Falta > 0 do
    begin
      // espera por um thread terminar
      if WaitForSingleObject(Sem, 100) = WAIT_OBJECT_0 then
        Dec(Falta);
      // deixa a VCL tratar suas mensagens
      Application.ProcessMessages;
    end;
  finally
    CloseHandle(Sem);
    Sem := 0;
  end;
end;


Cada thread deve executar este trecho de código ao terminar sua parte:
ReleaseSemaphore(Form1.Sem, 1, nil);



GOSTEI 0
Nildo

Nildo

30/05/2005

Eu gosto de usar Critical Sections no lugar de semáforos


GOSTEI 0
POSTAR