Synchronisieren der Ausführung mehrerer Threads

Um Racebedingungen und Deadlocks zu vermeiden, muss der Zugriff von mehreren Threads auf freigegebene Ressourcen synchronisiert werden. Außerdem ist eine Synchronisierung erforderlich, um sicherzustellen, dass interdependent Code in der richtigen Sequenz ausgeführt wird.

Es gibt eine Reihe von Objekten, deren Handles zum Synchronisieren mehrerer Threads verwendet werden können. Zu diesen Objekten gehören:

  • Konsoleneingabepuffer
  • Ereignisse
  • Mutexe
  • Prozesse
  • Semaphoren
  • Threads
  • Timer

Der Zustand jedes dieser Objekte wird entweder signalisiert oder nicht signalisiert. Wenn Sie ein Handle für eines dieser Objekte in einem Aufruf einer der Wartefunktionen angeben, wird die Ausführung des aufrufenden Threads blockiert, bis der Zustand des angegebenen Objekts signalisiert wird.

Einige dieser Objekte sind nützlich, um einen Thread zu blockieren, bis ein Ereignis auftritt. Beispielsweise wird ein Konsoleneingabepufferhandle signalisiert, wenn ungelesene Eingaben vorhanden sind, z. B. eine Tasteneingabe oder ein Mausklick. Prozess- und Threadhandles werden signalisiert, wenn der Prozess oder Thread beendet wird. Dadurch kann ein Prozess beispielsweise einen untergeordneten Prozess erstellen und dann seine eigene Ausführung blockieren, bis der neue Prozess beendet wurde.

Andere Objekte sind nützlich, um freigegebene Ressourcen vor dem gleichzeitigen Zugriff zu schützen. Beispielsweise können mehrere Threads jeweils über ein Handle für ein Mutex-Objekt verfügen. Vor dem Zugriff auf eine freigegebene Ressource müssen die Threads eine der Wartefunktionen aufrufen, um zu warten, bis der Zustand des Mutex signalisiert wird. Wenn der Mutex signalisiert wird, wird nur ein wartenden Thread für den Zugriff auf die Ressource freigegeben. Der Zustand des Mutex wird sofort auf nicht signalisiert zurückgesetzt, sodass alle anderen wartenden Threads blockiert bleiben. Wenn der Thread mit der Ressource abgeschlossen ist, muss der Zustand des Mutex auf signalisiert festgelegt werden, damit andere Threads auf die Ressource zugreifen können.

Für die Threads eines einzelnen Prozesses bieten Objekte mit kritischen Abschnitten eine effizientere Methode zur Synchronisierung als Mutexes. Ein kritischer Abschnitt wird wie ein Mutex verwendet, um jeweils einen Thread für die Verwendung der geschützten Ressource zu aktivieren. Ein Thread kann die EnterCriticalSection-Funktion verwenden, um den Besitz eines kritischen Abschnitts anzufordern. Wenn er bereits im Besitz eines anderen Threads ist, wird der anfordernde Thread blockiert. Ein Thread kann die TryEnterCriticalSection-Funktion verwenden, um den Besitz eines kritischen Abschnitts anzufordern, ohne zu blockieren, wenn der kritische Abschnitt nicht abgerufen wird. Nachdem er den Besitz erhalten hat, kann der Thread die geschützte Ressource verwenden. Die Ausführung der anderen Threads des Prozesses ist nicht betroffen, es sei denn, sie versuchen, in denselben kritischen Abschnitt zu gelangen.

Die WaitForInputIdle-Funktion bewirkt, dass ein Thread wartet, bis ein angegebener Prozess initialisiert ist, und wartet auf Benutzereingaben ohne ausstehende Eingabe. Das Aufrufen von WaitForInputIdle kann für die Synchronisierung übergeordneter und untergeordneter Prozesse nützlich sein, da CreateProcess zurückgibt, ohne darauf zu warten, dass der untergeordnete Prozess seine Initialisierung abgeschlossen hat.

Weitere Informationen finden Sie unter Synchronisierung.