高速ミューテックスと保護されたミューテックス

Windows 2000 以降、ドライバーは、IRQL <= APC_LEVEL で実行されるコードの相互排他オーバーヘッドが低い形式が必要な場合、高速ミューテックスを使用できます。 高速ミューテックスは、一度に 1 つのスレッドのみによる入力が必要なコード パスを保護できます。 保護されたコード パスを入力するため、スレッドはミューテックスを取得します。 別のスレッドが既にミューテックスを取得している場合、ミューテックスが解放されるまで、現在のスレッドの実行は中断されます。 保護されたコード パスを終了するため、スレッドはミューテックスを解放します。

Windows Server 2003 以降、ドライバーは保護ミューテックスを使用することもできます。 保護ミューテックスは、高速ミューテックスのドロップイン置換ですが、パフォーマンスが向上します。 高速ミューテックスと同様、保護ミューテックスは、一度に 1 つのスレッドのみによる入力が必要なコード パスを保護できます。 ただし、保護ミューテックスを使用するコードは、高速ミューテックスを使用するコードよりも高速に実行されます。

Windows 8 より前のバージョンの Windows では、保護ミューテックスは高速ミューテックスとは異なる方法で実装されています。 高速ミューテックスによって保護されるコード パスは、IRQL = APC_LEVEL で実行されます。 保護ミューテックスによって保護されるコード パスは、IRQL <= APC_LEVEL で実行されますが、すべての APC が無効になります。 これらの以前のバージョンの Windows では、保護ミューテックスの取得は、高速ミューテックスの取得よりも高速な操作になります。 ただし、これら 2 種類のミューテックスは同じように動作し、同じ制限が適用されます。 特に、IRQL = APC_LEVEL で呼び出すことが禁止されているカーネル ルーチンは、高速ミューテックスまたは保護ミューテックスによって保護されているコード パスから呼び出さないでください。

Windows 8 以降では、保護ミューテックスは高速ミューテックスとして実装されます。 保護ミューテックスまたは高速ミューテックスによって保護されているコード パスでは、ドライバー検証ツールは、IRQL = APC_LEVEL で発生するカーネル ルーチンへの呼び出しを処理します。 以前のバージョンの Windows と同様、保護ミューテックスまたは高速ミューテックスによって保護されているコード パスでは、APC_LEVEL で禁止されている呼び出しが禁止されます。

高速ミューテックス

高速ミューテックスは、FAST_MUTEX 構造によって表されます。 ドライバーは、FAST_MUTEX 構造に独自のストレージを割り当て、その構造を初期化する ExInitializeFastMutex ルーチンを呼び出します。

スレッドは、次のいずれかの方法で高速ミューテックスを取得します。

  • ExAcquireFastMutex ルーチンの呼び出し。 ミューテックスが既に別のスレッドによって取得されている場合、ミューテックスが使用可能になるまで、呼び出し元のスレッドの実行は中断されます。

  • ExTryToAcquireFastMutex ルーチンを呼び出して、現在のスレッドを中断せずに高速ミューテックスを取得しようとします。 ミューテックスが取得されたかどうかに関係なく、ルーチンは直ちに戻ります。 ExTryToAcquireFastMutex は、呼び出し元のミューテックスを正常に取得した場合は TRUE を返します。それ以外の場合は FALSE を返します。

スレッドは ExReleaseFastMutex を呼び出し、ExAcquireFastMutex または ExTryToAcquireFastMutex によって取得された高速ミューテックスを解放します。

高速ミューテックスによって保護されるコード パスは、IRQL = APC_LEVEL で実行されます。 ExAcquireFastMutexExTryToAcquireFastMutex は現在の IRQL をAPC_LEVEL に上げ、ExReleaseFastMutex は元の IRQL を復元します。 したがって、スレッドが高速ミューテックスを保持している間、すべての APC が無効になります。

コード パスが常に APC_LEVEL で実行されることが保証されている場合、ドライバーは代わりに ExAcquireFastMutexUnsafeExReleaseFastMutexUnsafe を呼び出し、高速ミューテックスを取得して解放できます。 これらのルーチンは現在の IRQL を変更せず、現在の IRQL が APC_LEVEL のときのみ安全に使用できます。

高速ミューテックスは再帰的に取得することができません。 既に高速ミューテックスを保持しているスレッドが取得しようとすると、そのスレッドはデッドロックされます。 高速ミューテックスは、IRQL <= APC_LEVEL で実行されるコードでのみ使用できます。

保護ミューテックス

保護ミューテックス (Windows Server 2003 以降で利用可能) は、高速ミューテックスと同じ機能を実行しますが、パフォーマンスが向上します。

Windows 8 以降では、保護ミューテックスと高速ミューテックスが同じように実装されます。

Windows 8 より前のバージョンの Windows では、保護ミューテックスは高速ミューテックスとは異なる方法で実装されています。 高速ミューテックスを取得すると、現在の IRQL が APC_LEVEL に上がり、保護ミューテックスを取得すると、保護された領域に入ります。これは、より高速な操作です。 保護された領域について詳しくは、「クリティカル領域と保護された領域」をご覧ください。

保護ミューテックスは、KGUARDED_MUTEX 構造によって表されます。 ドライバーは、KGUARDED_MUTEX 構造に独自のストレージを割り当て、構造を初期化する KeInitializeGuardedMutex ルーチンを呼び出します。

スレッドは、次のいずれかの方法で保護ミューテックスを取得します。

  • KeAcquireGuardedMutex を呼び出します。 ミューテックスが既に別のスレッドによって取得されている場合、ミューテックスが使用可能になるまで、呼び出し元のスレッドの実行は中断されます。

  • KeTryToAcquireGuardedMutex を呼び出し、現在のスレッドを中断せずに、保護ミューテックスを取得しようとします。 ミューテックスが取得されたかどうかに関係なく、ルーチンは直ちに戻ります。 KeTryToAcquireGuardedMutex は、呼び出し元のミューテックスを正常に取得した場合は TRUE を返します。それ以外の場合は FALSE を返します。

スレッドは、KeReleaseGuardedMutex を呼び出し、KeAcquireGuardedMutex または KeTryToAcquireGuardedMutex によって取得された保護ミューテックスを解放します。

保護ミューテックスを保持するスレッドは、保護された領域内で暗黙的に実行されます。 KeAcquireGuardedMutexKeTryToAcquireGuardedMutex は保護された領域に入り、KeReleaseGuardedMutex はその領域から出ます。 スレッドが保護ミューテックスを保持している間、すべての APC が無効になります。

コード パスがすべての APC を無効にした状態で実行されることが保証されている場合、ドライバーは代わりに KeAcquireGuardedMutexUnsafeKeReleaseGuardedMutexUnsafe を使用し、保護ミューテックスを取得して解放できます。 これらのルーチンは、保護された領域に入ったり出たりせず、既に存在している保護された領域内、または IRQL = APC_LEVEL でのみ使用できます。

保護ミューテックスを再帰的に取得することはできません。 既に保護ミューテックスを保持しているスレッドが取得しようとすると、そのスレッドはデッドロックされます。 保護ミューテックスは、IRQL <= APC_LEVEL で実行されるコードでのみ使用できます。