Afficher : Delphi C++
Préférences d'affichage

Attente de l'achèvement d'une tâche

De RAD Studio

Remonter à Coordination de threads - Index

Parfois, il est nécessaire d'attendre qu'un thread termine une opération au lieu d'attendre la fin de l'exécution d'un thread particulier. Pour ce faire, utilisez un objet événement. Les objets événements (System.SyncObjs.TEvent) doivent être créés avec une portée globale afin qu'ils puissent agir comme des signaux visibles pour tous les threads.

Quand un thread termine une opération dont dépendent d'autres threads, il appelle TEvent.SetEvent. SetEvent active le signal afin que les autres threads le surveillant sachent que l'opération a été achevée. Pour désactiver le signal, utilisez la méthode ResetEvent.

Par exemple, imaginons une situation dans laquelle vous devez attendre la fin de l'exécution de plusieurs threads au lieu d'un seul. Comme vous ne savez pas quel sera le dernier thread, vous ne pouvez pas utiliser la méthode WaitFor de l'un d'eux. A la place, vous pouvez faire en sorte que chaque thread incrémente un compteur à la fin de son exécution et que le dernier thread signale l'achèvement de l'exécution de tous les threads en générant un événement.

Le code suivant montre la fin du gestionnaire d'événement System.Classes.TThread.OnTerminate de tous les threads dont l'exécution doit être achevée. CounterGuard est un objet section critique global qui évite l'utilisation simultanée du compteur par plusieurs threads. Counter est une variable globale qui compte le nombre de threads dont l'exécution est achevée.



 procedure TDataModule.TaskThreadTerminate(Sender: TObject);
 begin
 ...
 CounterGuard.Acquire; {obtenir un verrou sur le compteur}
 Dec(Counter);   { décrémenter la variable globale du compteur }
 if Counter = 0 then
 Event1.SetEvent; { signaler s'il s'agit du dernier thread }
 CounterGuard.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 global
 Event1->SetEvent(); // signale si c'est le dernier thread
 CounterGuard->Release(); // libère le verrou sur le compteur
 }



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

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 durée spécifiée.

wrError

Une erreur a eu lieu pendant l'attente.



Le code suivant montre comment le thread principal lance les threads de tâche et reprend la main lorsque leur exécution est achevée :



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



 Event1->ResetEvent(); // Efface l'événement avant de lancer les threads
 for (int i = 0; i < Counter; i++)
 new TaskThread(false); // Crée et lance les threads de tâche
 if (Event1->WaitFor(20000) != wrSignaled)
 throw Exception;
 // poursuivre maintenant dans le thread principal, toutes les tâches sont finies



Remarque :  Si vous ne voulez pas cesser d'attendre un é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.

Voir aussi

Autres langues