Schnelle Mutexes und bewachte Mutexes

Ab Windows 2000 können Treiber schnelle Mutexes verwenden, wenn sie eine Form des gegenseitigen Ausschlusses mit geringem Aufwand für Code benötigen, der unter IRQL <= APC_LEVEL ausgeführt wird. Ein schneller Mutex kann einen Codepfad schützen, der jeweils nur von einem Thread eingegeben werden muss. Um den geschützten Codepfad einzugeben, ruft der Thread den Mutex ab. Wenn der Mutex bereits von einem anderen Thread abgerufen wurde, wird die Ausführung des aktuellen Threads angehalten, bis der Mutex freigegeben wird. Um den geschützten Codepfad zu beenden, gibt der Thread den Mutex frei.

Ab Windows Server 2003 können Treiber auch geschützte Mutexe verwenden. Bewachte Mutexes sind Ersatz für schnelle Mutexes, bieten jedoch eine bessere Leistung. Wie ein schneller Mutex kann ein bewachter Mutex einen Codepfad schützen, der jeweils nur von einem Thread eingegeben werden muss. Code, der bewachte Mutexes verwendet, wird jedoch schneller ausgeführt als Code, der schnelle Mutexes verwendet.

In Windows-Versionen vor Windows 8 werden bewachte Mutexe anders implementiert als schnelle Mutexes. Ein Codepfad, der durch einen schnellen Mutex geschützt ist, wird unter IRQL = APC_LEVEL ausgeführt. Ein Codepfad, der durch einen geschützten Mutex geschützt ist, wird unter IRQL <= APC_LEVEL ausgeführt, aber alle APCs deaktiviert. In diesen früheren Versionen von Windows ist der Erwerb eines bewachten Mutex schneller als der Erwerb eines schnellen Mutex. Diese beiden Arten von Mutex verhalten sich jedoch identisch und unterliegen den gleichen Einschränkungen. Insbesondere sollten Kernelroutinen, die für den Aufruf von IRQL = APC_LEVEL unzulässig sind, nicht aus einem Codepfad aufgerufen werden, der entweder durch einen schnellen Mutex oder einen geschützten Mutex geschützt ist.

Ab Windows 8 werden bewachte Mutexe als schnelle Mutexe implementiert. In einem Codepfad, der durch einen bewachten Mutex oder einen schnellen Mutex geschützt ist, behandelt Driver Verifier Aufrufe von Kernelroutinen wie bei IRQL = APC_LEVEL. Wie in früheren Versionen von Windows sind Aufrufe, die bei APC_LEVEL illegal sind, in einem Codepfad illegal, der durch einen geschützten Mutex oder einen schnellen Mutex geschützt ist.

Fast Mutexes

Ein schneller Mutex wird durch eine FAST_MUTEX-Struktur dargestellt. Der Treiber weist einen eigenen Speicher für eine FAST_MUTEX-Struktur zu und ruft dann die ExInitializeFastMutex-Routine auf, um die Struktur zu initialisieren.

Ein Thread erhält einen schnellen Mutex, indem er eine der folgenden Aktionen ausführt:

  • Aufrufen der ExAcquireFastMutex-Routine . Wenn der Mutex bereits von einem anderen Thread abgerufen wurde, wird die Ausführung des aufrufenden Threads angehalten, bis der Mutex verfügbar wird.

  • Aufrufen der ExTryToAcquireFastMutex-Routine , um zu versuchen, den schnellen Mutex zu erhalten, ohne den aktuellen Thread anzusetzen. Die Routine wird sofort zurückgegeben, unabhängig davon, ob der Mutex erworben wurde. ExTryToAcquireFastMutex gibt TRUE zurück, wenn der Mutex für den Aufrufer erfolgreich erworben wurde. Andernfalls wird FALSE zurückgegeben.

Ein Thread ruft ExReleaseFastMutex auf, um einen schnellen Mutex freizugeben, der entweder von ExAcquireFastMutex oder ExTryToAcquireFastMutex erworben wurde.

Ein Codepfad, der durch einen schnellen Mutex geschützt ist, wird unter IRQL = APC_LEVEL ausgeführt. ExAcquireFastMutex und ExTryToAcquireFastMutex heben die aktuelle IRQL auf APC_LEVEL an, und ExReleaseFastMutex stellt den ursprünglichen IRQL wieder her. Daher sind alle APCs deaktiviert, während der Thread einen schnellen Mutex enthält.

Wenn garantiert wird, dass ein Codepfad immer bei APC_LEVEL ausgeführt wird, kann der Treiber stattdessen ExAcquireFastMutexUnsafe und ExReleaseFastMutexUnsafe aufrufen, um einen schnellen Mutex abzurufen und freizugeben. Diese Routinen ändern den aktuellen IRQL nicht und können nur dann sicher verwendet werden, wenn die aktuelle IRQL APC_LEVEL ist.

Schnelle Mutexe können nicht rekursiv erworben werden. Wenn ein Thread, der bereits einen schnellen Mutex enthält, versucht, ihn zu erwerben, wird dieser Thread deadlockt. Schnelle Mutexes können nur in Code verwendet werden, der unter IRQL <= APC_LEVEL ausgeführt wird.

Bewachte Mutexes

Geschützte Mutexes, die ab Windows Server 2003 verfügbar sind, haben die gleiche Funktion wie schnelle Mutexe, aber mit höherer Leistung.

Ab Windows 8 werden bewachte Mutexes und schnelle Mutexe identisch implementiert.

In Windows-Versionen vor Windows 8 werden bewachte Mutexe anders implementiert als schnelle Mutexes. Durch den Erwerb eines schnellen Mutex wird der aktuelle IRQL auf APC_LEVEL erhöht, während der Erwerb eines bewachten Mutex in eine bewachte Region eintritt, was ein schnellerer Vorgang ist. Weitere Informationen zu bewachten Regionen finden Sie unter Kritische Regionen und geschützte Regionen.

Ein bewachter Mutex wird durch eine KGUARDED_MUTEX-Struktur dargestellt. Der Treiber weist einen eigenen Speicher für eine KGUARDED_MUTEX-Struktur zu und ruft dann die KeInitializeGuardedMutex-Routine auf, um die Struktur zu initialisieren.

Ein Thread ruft einen geschützten Mutex ab, indem er eine der folgenden Aktionen ausführt:

  • Aufrufen von KeAcquireGuardedMutex. Wenn der Mutex bereits von einem anderen Thread abgerufen wurde, wird die Ausführung des aufrufenden Threads angehalten, bis der Mutex verfügbar wird.

  • Rufen Sie KeTryToAcquireGuardedMutex auf, um zu versuchen, den überwachten Mutex zu erhalten, ohne den aktuellen Thread anzusetzen. Die Routine wird sofort zurückgegeben, unabhängig davon, ob der Mutex erworben wurde. KeTryToAcquireGuardedMutex gibt TRUE zurück, wenn der Mutex für den Aufrufer erfolgreich erworben wurde. Andernfalls wird FALSE zurückgegeben.

Ein Thread ruft KeReleaseGuardedMutex auf, um einen bewachten Mutex freizugeben, der entweder von KeAcquireGuardedMutex oder KeTryToAcquireGuardedMutex erworben wurde.

Ein Thread, der einen bewachten Mutex enthält, wird implizit innerhalb eines bewachten Bereichs ausgeführt. KeAcquireGuardedMutex und KeTryToAcquireGuardedMutex gelangen in die bewachte Region, während KeReleaseGuardedMutex sie verlässt. Alle APCs sind deaktiviert, während der Thread einen geschützten Mutex enthält.

Wenn garantiert wird, dass ein Codepfad mit deaktivierten APCs ausgeführt wird, kann der Treiber stattdessen KeAcquireGuardedMutexUnsafe und KeReleaseGuardedMutexUnsafe verwenden, um den geschützten Mutex zu erwerben und freizugeben. Diese Routinen betreten oder verlassen keine bewachte Region und können nur innerhalb einer bereits vorhandenen bewachten Region oder unter IRQL = APC_LEVEL verwendet werden.

Bewachte Mutexe können nicht rekursiv erworben werden. Wenn ein Thread, der bereits einen geschützten Mutex enthält, versucht, ihn zu erwerben, wird dieser Thread deadlockt. Bewachte Mutexes können nur in Code verwendet werden, der unter IRQL <= APC_LEVEL ausgeführt wird.