Freigeben über


Kritische Abschnittsobjekte

Ein kritisches Abschnittsobjekt bietet eine Synchronisierung ähnlich wie bei einem Mutex-Objekt, mit der Ausnahme, dass ein kritischer Abschnitt nur von den Threads eines einzelnen Prozesses verwendet werden kann. Kritische Abschnittsobjekte können nicht über Prozesse hinweg freigegeben werden.

Ereignis-, Mutex- und Semaphorobjekte können auch in einer Einzelprozessanwendung verwendet werden, kritische Abschnittsobjekte bieten jedoch einen etwas schnelleren, effizienteren Mechanismus für die gegenseitige Ausschlusssynchronisierung (einen prozessorspezifischen Test und eine Set-Anweisung). Wie ein Mutex-Objekt kann ein kritisches Abschnittsobjekt jeweils nur einem Thread gehören, wodurch es nützlich ist, eine freigegebene Ressource vor gleichzeitigem Zugriff zu schützen. Im Gegensatz zu einem Mutex-Objekt gibt es keine Möglichkeit, festzustellen, ob ein kritischer Abschnitt abgebrochen wurde.

Ab Windows Server 2003 mit Service Pack 1 (SP1) werden Threads, die auf einem kritischen Abschnitt warten, den kritischen Abschnitt nicht auf first-come-First-Serve-Basis abrufen. Diese Änderung erhöht die Leistung für die meisten Code erheblich. Einige Anwendungen sind jedoch von der FiFO-Sortierung (First-In, First-Out) abhängig und können bei aktuellen Versionen von Windows schlecht oder gar nicht ausgeführt werden (z. B. Anwendungen, die kritische Abschnitte als Rate-Limiter verwenden). Um sicherzustellen, dass Ihr Code weiterhin ordnungsgemäß funktioniert, müssen Sie möglicherweise eine zusätzliche Synchronisierungsebene hinzufügen. Angenommen, Sie haben einen Produzententhread und einen Consumerthread, der ein kritisches Abschnittsobjekt verwendet, um ihre Arbeit zu synchronisieren. Erstellen Sie zwei Ereignisobjekte, eine für jeden Thread, der verwendet werden soll, um zu signalisieren, dass der andere Thread fortgesetzt werden kann. Der Consumerthread wartet darauf, dass der Produzent sein Ereignis signalisiert, bevor er den kritischen Abschnitt eingibt, und der Produzententhread wartet, bis der Consumerthread sein Ereignis signalisiert, bevor er in den kritischen Abschnitt eintritt. Nachdem jeder Thread den kritischen Abschnitt verlässt, signalisiert er sein Ereignis, um den anderen Thread freizugeben.

Windows Server 2003 und Windows XP: Threads, die auf einen kritischen Abschnitt warten, werden einer Wartewarteschlange hinzugefügt; sie werden weckt und erwerben in der Regel den kritischen Abschnitt in der Reihenfolge, in der sie der Warteschlange hinzugefügt wurden. Wenn dieser Warteschlange jedoch Threads schnell genug hinzugefügt werden, kann die Leistung aufgrund der Zeit beeinträchtigt werden, die für jedes Wartethread erforderlich ist.

Der Prozess ist für die Zuordnung des von einem kritischen Abschnitt verwendeten Speichers verantwortlich. Dies geschieht in der Regel durch einfaches Deklarieren einer Variablen vom Typ CRITICAL_SECTION. Bevor die Threads des Prozesses ihn verwenden können, initialisieren Sie den kritischen Abschnitt mithilfe der InitializeCriticalSection oder InitializeCriticalSectionAndSpinCount Funktion.

Ein Thread verwendet die EnterCriticalSection oder TryEnterCriticalSection-Funktion, um den Besitz eines kritischen Abschnitts anzufordern. Es verwendet die LeaveCriticalSection-Funktion, um den Besitz eines kritischen Abschnitts freizugeben. Wenn das kritische Abschnittsobjekt derzeit einem anderen Thread gehört, EnterCriticalSection auf unbestimmte Zeit auf den Besitz wartet. Wenn ein Mutex-Objekt dagegen für den gegenseitigen Ausschluss verwendet wird, akzeptieren die Wait-Funktionen ein bestimmtes Timeoutintervall akzeptieren. Die TryEnterCriticalSection-Funktion versucht, einen kritischen Abschnitt einzugeben, ohne den aufrufenden Thread zu blockieren.

Wenn ein Thread einen kritischen Abschnitt besitzt, kann er zusätzliche Aufrufe an EnterCriticalSection oder TryEnterCriticalSection durchführen, ohne die Ausführung zu blockieren. Dadurch wird verhindert, dass ein Thread sich selbst blockiert, während er auf einen kritischen Abschnitt wartet, den er bereits besitzt. Um den Besitz freizugeben, muss der Thread LeaveCriticalSection einmal aufrufen, wenn er den kritischen Abschnitt eingegeben hat. Es gibt keine Garantie für die Reihenfolge, in der wartende Threads den Besitz des kritischen Abschnitts erwerben.

Ein Thread verwendet die InitializeCriticalSectionAndSpinCount oder SetCriticalSectionSpinCount- funktion, um eine Drehzahl für das kritische Abschnittsobjekt anzugeben. Wenn ein Thread versucht, einen kritischen Abschnitt zu erhalten, der gesperrt ist, wechselt der Thread in eine Schleife, überprüft, ob die Sperre losgelassen wird und wenn die Sperre nicht losgelassen wird, wechselt der Thread in den Ruhezustand. Auf Einzelprozessorsystemen wird die Drehzahl ignoriert, und die kritische Drehzahl des Abschnitts wird auf 0 (Null) festgelegt. Wenn der kritische Abschnitt auf Multiprozessorsystemen nicht verfügbar ist, dreht sich der aufrufende Thread dwSpinCount Zeiten vor dem Ausführen eines Wartezeitvorgangs für einen Semaphor, der dem kritischen Abschnitt zugeordnet ist. Wenn der kritische Abschnitt während des Drehvorgangs frei wird, vermeidet der aufrufende Thread den Wartevorgang.

Jeder Thread des Prozesses kann die DeleteCriticalSection--Funktion verwenden, um die Systemressourcen freizugeben, die zugeordnet werden, wenn das kritische Abschnittsobjekt initialisiert wird. Nachdem diese Funktion aufgerufen wurde, kann das kritische Abschnittsobjekt nicht für die Synchronisierung verwendet werden.

Wenn ein kritisches Abschnittsobjekt gehört, sind die einzigen anderen Threads betroffen, die auf den Besitz in einem Aufruf von EnterCriticalSectionwarten. Threads, die nicht warten, können weiterhin ausgeführt werden.

Mutex-Objekte

Verwenden kritischer Abschnittsobjekte