Attente des threads

De RAD Studio
Aller à : navigation, rechercher

Remonter à Comment construire des applications multithreads

Voici les procédures qui peuvent être utilisées pour attendre les threads.

  • Attendre la fin d'exécution d'un thread
  • Attendre l'achèvement d'une tâche
  • Vérifier si un autre thread attend la fin de votre thread

Pour attendre la fin d'exécution d'un thread

  1. Utilisez la méthode WaitFor de l'autre thread.
  2. Codez votre logique. Par exemple, le code suivant attend qu'un autre thread remplisse un objet liste de threads avant d'accéder aux objets de la liste :
 if ListFillingThread.WaitFor then
 begin
   with ThreadList1.LockList do
   begin
 				for I := 0 to Count - 1 do
       ProcessItem(Items[I];
   end;
   ThreadList1.UnlockList;
 end;
 if( ListFillingThread->WaitFor() ) {
   TList* list = ThreadList1>LockList();
   for( int i = 0; i < list->Count; i++ ) {
     DoSomething( list->Items[i] );
   }
   ThreadList1>UnlockList();
 }


Pour attendre l'achèvement d'une tâche

  1. Créez un objet TEvent de portée globale.
  2. Quand un thread termine une opération que d'autres threads attendent, il appelle TEvent.SetEvent.
  3. Pour désactiver le signal, appelez TEvent.ResetEvent.

L'exemple suivant est un gestionnaire d'événement OnTerminate qui utilise un compteur global dans une section critique pour mémoriser le nombre de threads terminés. Quand Counter atteint 0, le gestionnaire appelle la méthode SetEvent pour signaler que tous les processus sont terminés :



 procedure TDataModule.TaskTerminateThread(Sender: TObject);
 begin
   ...
   CounterGuard.Acquire; {obtient un verrou sur le compteur}
   Dec(Counter); { décrémente la variable globale du compteur }
   if Counter = 0 then
     Event1.SetEvent; { signale s'il s'agit du dernier thread }
   Counter.Release; {déverrouiller le compteur}
   ...
 end;



 void __fastcall TDataModule::TaskThreadTerminate( TObject *Sender ) {
   ...
   CounterGuard->Acquire(); // verrouille le compteur
   if( ––Counter == 0 )      // décrémente le compteur
     Event1->SetEvent();    // signale si c'est le dernier thread
   CounterGuard->Release(); // libère le verrouillage
 }



Le thread principal initialise la variable Counter, lance les threads de tâches et attend le signal indiquant l'achèvement de l'exécution de tous les threads en appelant la méthode TEvent::WaitFor. WaitFor attend l'activation du signal pendant une durée spécifiée et renvoie l'une des valeurs du tableau ci-dessous.

L'exemple de code suivant montre comment le thread principal lance les threads de tâches et reprend la main lorsque leur exécution est achevée.



 Event1.ResetEvent; {efface l'événement avant de lancer les threads}
 for i := 1 to Counter do
   TaskThread.Create(False); {crée et lance les threads de tâches}
 if Event1.WaitFor(20000) <> wrSignaled then
   raise Exception;
 {poursuite avec le thread principal}



 Event1>ResetEvent();  // efface l'événement avant de lancer les threads
 for( int i = 0; i < Counter; i++ ) {
   new TaskThread( false );
 if( Event1>WaitFor(20000) != wrSignaled )
   throw Exception;
 // poursuite maintenant avec le thread principal



Remarque :  Si vous ne voulez pas cesser d'attendre un gestionnaire d'événement après un délai spécifié, transmettez à la méthode WaitFor une valeur de paramètre INFINITE. Faites attention en utilisant INFINITE, car cela peut provoquer le blocage du thread si le signal attendu n'arrive pas.

Pour vérifier si un autre thread attend la fin de votre thread

  1. Dans votre procédure Execute, implémentez la méthode Terminate en testant la valeur de la propriété Terminated.
  2. Voici un moyen de coder la logique :
 procedure TMyThread.Execute;
 begin
   while not Terminated do
     PerformSomeTask;
 end;
 void __fastcall TMyThread::Execute() {
   while( !Terminated )
     DoSomething();
 }


Valeurs renvoyées par WaitFor:



Valeur

Signification

wrSignaled

Le signal de l'objet événement a été activé.

wrTimeout

La durée spécifiée s'est écoulée sans que le signal soit défini.

wrAbandoned

L'objet événement a été détruit avant l'écoulement de la période d'attente.

wrError

Une erreur a eu lieu pendant l'attente.



Voir aussi