Warten, bis eine Aufgabe ausgeführt ist

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Auf andere Threads warten


Es gibt Situationen, in denen nicht gewartet werden muss, bis ein Thread vollständig ausgeführt ist, sondern nur solange, bis er eine bestimmte Operation abgeschlossen hat. In solchen Fällen finden Ereignisobjekte Verwendung. Diese Objekte (System.SyncObjs.TEvent) sollten mit globalem Gültigkeitsbereich erzeugt werden, sodass sie wie Signale funktionieren, die von jedem Thread erkannt werden können.

Wenn ein Thread eine Operation beendet, von der andere Threads abhängig sind, ruft er TEvent.SetEvent auf. SetEvent aktiviert das Signal, sodass andere Threads, welche dieses Signal auswerten, den Abschluss einer Operation feststellen können. Zur Deaktivierung des Signals verwenden Sie die Methode ResetEvent.

Das folgende Beispiel basiert auf einer Situation, in der nicht nur auf die Ausführung eines einzelnen Threads, sondern auf die vollständige Ausführung mehrerer Threads gewartet werden muss. Da nicht bekannt ist, welcher Thread zuletzt beendet wird, kann nicht einfach die Methode WaitFor eines der Threads aufgerufen werden. Stattdessen wird ein Zähler implementiert, den jeder Thread bei seiner Beendigung erhöht. Der letzte Thread signalisiert dann durch das Auslösen eines Ereignisses, dass die Ausführung aller Threads abgeschlossen ist.

Nachfolgend finden Sie den letzten Teil der Ereignisbehandlungsroutine System.Classes.TThread.OnTerminate für alle Threads, die beendet werden müssen. CounterGuard ist ein globaler, kritischer Abschnitt, der den gleichzeitigen Zugriff mehrerer Threads auf den Zähler verhindert. Counter ist eine globale Variable, in der die Zahl der Threads gespeichert wird, die vollständig ausgeführt wurden.

 procedure TDataModule.TaskThreadTerminate(Sender: TObject);
 begin
 ...
 CounterGuard.Acquire; { Zähler mit einer Sperre belegen }
 Dec(Counter);   { Wert der globalen Zählervariable verringern }
 if Counter = 0 then
 Event1.SetEvent; { Signalisieren, ob es der letzte Thread ist }
 CounterGuard.Release; { Sperre vom Zähler entfernen }
 ...
 end;
 void __fastcall TDataModule::TaskThreadTerminate(TObject *Sender)
 {
 ...
 CounterGuard->Acquire(); // Zähler mit einer Sperre belegen
 if (--Counter == 0) // Wert der globalen Zähler-Variable verringern
 Event1->SetEvent(); // Signalisieren, ob es der letzte Thread ist
 CounterGuard->Release(); // Sperre vom Zähler entfernen
 }

Der Haupt-Thread initialisiert die Variable Counter, startet den Task-Threads und fragt über die Methode WaitFor den Signalzustand ab. WaitFor wartet eine bestimmte Zeit, ob das Signal gesetzt wird, und gibt einen der in der folgenden Tabelle aufgeführten Werte zurück.

Rückgabewerte von WaitFor:

Wert Bedeutung

wrSignaled

Das Signal des Ereignisses war gesetzt.

wrTimeout

Die festgelegte Zeitspanne ist verstrichen, ohne dass das Signal gesetzt wurde.

wrAbandoned

Das Ereignisobjekt wurde freigegeben, bevor das Time-out-Intervall abgelaufen war.

wrError

Beim Warten ist ein Fehler aufgetreten.


Der folgende Quelltext zeigt, wie der Haupt-Thread die einzelnen Aufgaben-Threads startet und nach deren Beendigung seine Operation wieder aufnimmt:

 Event1.ResetEvent(); { Ereignis vor der Ausführung der Threads zurücksetzen }
 for i := 1 to Counter do
 TaskThread.Create(False); { Aufgaben-Threads erzeugen und ausführen }
 if Event1.WaitFor(20000) <> wrSignaled then
 raise Exception;
 { nun den Haupt-Threads fortsetzen Alle Aufgaben-Threads sind beendet }
 Event1->ResetEvent(); // Ereignis löschen, bevor die Threads gestartet werden
 for (int i = 0; i < Counter; i++)
 new TaskThread(false); // Task-Threads erstellen und starten
 if (Event1->WaitFor(20000) != wrSignaled)
 throw Exception;
 // Nun mit dem Haupt-Thread fortfahren; alle Task-Threads sind beendet.

Hinweis:  Wenn die Wartezeit nicht durch einen festen Wert beschränkt sein soll, übergeben Sie der Methode WaitFor den Parameterwert INFINITE. Allerdings ist hier Vorsicht geboten, denn wenn das Signal aus irgendwelchen Gründen nie empfangen wird, bleibt der Thread einfach stehen.

Siehe auch