デッドロック検出は、スピンロック、ミューテックス、高速ミューテックスなど、ロックが必要なリソースのドライバーによる使用方法を監視します。 このドライバー検証ツール オプションは、将来デッドロックを引き起こす可能性があるコード ロジックを検出します。
ドライバー検証ツールのデッドロック検出オプションと !deadlock カーネル デバッガー拡張機能は、コードがこれらのリソースの不適切な使用を回避するための効果的なツールです。
デッドロック検出は、Windows XP 以降のバージョンの Windows でのみサポートされます。
デッドロックの原因
デッドロックは、2 つ以上のスレッドが一部のリソースで競合した場合に発生し、実行が不可能な方法で発生します。
デッドロックの最も一般的な形式は、他のスレッドが所有するリソースを 2 つ以上のスレッドが待機するときに発生します。 これを次に示します。
| スレッド 1 | スレッド 2 |
|---|---|
| ロック A を受け取ります | ロック B を取得します |
| 要求ロック B | ロック A の要求 |
両方のシーケンスが同時に発生した場合、スレッド 1 はスレッド 2 によって所有されているためロック B を取得しません。スレッド 2 はスレッド 1 によって所有されているためロック A を取得しません。 せいぜい、これにより関係するスレッドが停止し、最悪の場合、システムが応答を停止します。
デッドロックは、2 つのスレッドと 2 つのリソースに限定されません。 3 つのスレッドと 3 つのロックの間の 3 方向のデッドロックは一般的であり、5 部または 6 部のデッドロックが発生することがあります。 これらのデッドロックは、同時に発生する多くのことに依存するため、ある程度の "不運" が必要です。 ただし、ロックの取得が離れているほど、これらの可能性が高くなります。
スレッドが既に所有しているロックを取得しようとすると、単一スレッドのデッドロックが発生する可能性があります。
すべてのデッドロックの共通の分母は、ロック階層が尊重されないことです。 一度に複数のロックを取得する必要がある場合は常に、各ロックの優先順位が明確である必要があります。 ある時点で B の前に A を、別の時点で C の前に B を取ると、階層は A から B から C になります。 つまり、A は B または C の後に取得しないでください。B は C の後に取得することはできません。
デッドロックが発生する可能性がない場合でも、ロック階層に従う必要があります。コードを維持するプロセスでは、デッドロックが誤って導入されやすいためです。
デッドロックの原因となる可能性があるリソース
最も明確なデッドロックは、 所有リソース の結果です。 これには、スピン ロック、ミューテックス、高速ミューテックス、および ERESOURCE が含まれます。
取得ではなく通知されるリソース (イベントや LPC ポートなど) は、はるかにあいまいなデッドロックを引き起こす傾向があります。 もちろん、コードがこれらのリソースを誤用して、2 つのスレッドが互いの完了を無期限に待機するようにすることは、もちろん可能であり、あまりにも一般的です。 ただし、これらのリソースは実際には特定のスレッドによって所有されていないため、問題を起こしているスレッドを確実に識別することはできません。
ドライバー検証ツールのデッドロック検出オプションは、スピン ロック、ミューテックス、高速ミューテックスを含む可能性のあるデッドロックを検索します。 ERESOURCE の使用を監視したり、所有されていないリソースの使用を監視したりすることはありません。
デッドロック検出の効果
ドライバー検証ツールのデッドロック検出ルーチンは、必ずしも同時ではないロック階層違反を検出します。 ほとんどの場合、これらの違反は、チャンスが与えられたときにデッドロックするコード パスを特定します。
潜在的なデッドロックを見つけるために、ドライバー検証ツールはリソース取得順序のグラフを作成し、ループをチェックします。 リソースごとにノードを作成し、あるロックが別のロックの前に取得されるたびに矢印を描画する場合、パス ループはロック階層違反を表します。
ドライバー検証ツールは、これらの違反のいずれかが検出されるとバグ チェックを発行します。 これは、実際のデッドロックが発生する前に発生します。
注
競合するコード パスが同時に発生することは決してない場合でも、ロック階層違反が発生した場合は、それらのパスを書き換える必要があります。 このようなコードは、コードが少し書き直された場合に実際のデッドロックを引き起こす可能性がある "デッドロックが発生するのを待機しています" です。
デッドロック検出で違反が検出されると、バグ チェック0xC4が発行されます。 このバグ チェックの最初のパラメーターは、正確な違反を示します。 違反の可能性は次のとおりです。
ロック階層違反に関係する 2 つ以上のスレッド
既に共有所有者であるリソースを排他的に取得しようとするスレッド(排他的に所有されているリソースは共有で使用可能ですが、共有リソースは排他的に取得することはできません)。
同じリソースを 2 回取得しようとするスレッド (自己デッドロック)
最初に取得されずに解放されたリソース
取得したスレッドとは異なるスレッドによって解放されるリソース
複数回初期化されたリソース、またはまったく初期化されていないリソース
リソースを保持したまま削除されるスレッド
Windows 7 以降、ドライバー検証ツールは、発生する可能性のあるデッドロックを予測できます。 たとえば、同じKSPIN_LOCKデータ構造を通常のスピン ロックとスタック キュースピン ロックの両方として使用しようとしています。
バグ チェック パラメーターの一覧については、バグ チェック 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION) を参照してください。
デッドロック検出の監視
デッドロック検出で違反が検出されると、 !deadlock カーネル デバッガー拡張機能を使用して、発生した内容を正確に調査できます。 ロック階層トポロジと、ロックが最初に取得された時点の各スレッドの呼び出し履歴を表示できます。
Windows 用デバッグ ツール パッケージのドキュメントには、 !deadlock 拡張機能の詳細な例とデバッガー拡張機能に関する一般的な情報があります。 詳細については、「 Windows デバッグ 」を参照してください。
このオプションのアクティブ化
注
このオプションは、カーネル同期遅延ファジーと互換性がありません
ドライバー検証ツール マネージャーまたは Verifier.exe コマンド ラインを使用して、1 つ以上のドライバーのデッドロック検出機能をアクティブ化できます。 詳細については、「 ドライバー検証ツールオプションの選択」を参照してください。
コマンド ラインで
コマンド ラインでは、デッドロック検出オプションは ビット 5 (0x20) で表されます。 デッドロック検出をアクティブにするには、0x20のフラグ値を使用するか、フラグ値に0x20を追加します。 例えば次が挙げられます。
verifier /flags 0x20 /driver MyDriver.sysこの機能は、次の起動時にアクティブになります。
Windows Vista 以降のバージョンの Windows では、 /volatile パラメーターをコマンドに追加することで、コンピューターを再起動せずにデッドロック検出をアクティブ化および非アクティブ化することもできます。 例えば次が挙げられます。
verifier /volatile /flags 0x20 /adddriver MyDriver.sysこの設定はすぐに有効ですが、コンピューターをシャットダウンまたは再起動すると失われます。 詳細については、「 揮発性設定の使用」を参照してください。
デッドロック検出機能は、標準設定にも含まれています。 例えば次が挙げられます。
verifier /standard /driver MyDriver.sysドライバー検証ツール マネージャーの使用
(コード開発者向けの) [カスタム設定の作成] を選択し、[次へ] を選択します。
完全な一覧から [個々の設定を選択] を選択します。
[デッドロックの検出] を選択 (チェック) します。
デッドロック検出機能は、標準設定にも含まれています。 この機能を使用するには、 ドライバー検証ツール マネージャーで、[ 標準設定の作成] を選択します。