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

De RAD Studio
Aller à : navigation, rechercher

Remonter à Attente des autres threads


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; { obtain a lock on the counter }
  Dec(Counter);   { decrement the global counter variable }
  if Counter = 0 then
    Event1.SetEvent; { signal if this is the last thread }
  CounterGuard.Release; { release the lock on the counter }
  // ...
end;
void __fastcall TDataModule::TaskThreadTerminate(TObject *Sender) {
	// ...
	CounterGuard->Acquire(); // lock the counter
	if (--Counter == 0) // decrement the global counter
			Event1->SetEvent(); // signal if this is the last thread
	CounterGuard->Release(); // release the lock on the counter
}

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; { clear the event before launching the threads }
 for i := 1 to Counter do
 TaskThread.Create(False); { create and launch task threads }
 if Event1.WaitFor(20000) <> wrSignaled then
 raise Exception;
 { now continue with the main thread. All task threads have finished }
Event1->ResetEvent(); // clear the event before launching the threads
for (int i = 0; i < Counter; i++)
	new TaskThread(false); // create and launch task threads
if (Event1->WaitFor(20000) != wrSignaled)
	throw Exception;
// now continue with the main thread, all task threads have finished

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