デッドロックの検出
デッドロック検出は、ロックする必要があるリソース (スピン ロック、ミューテックス、高速ミューテックス) のドライバーの使用を監視します。 このドライバー検証ツール オプションは、将来デッドロックを引き起こす可能性があるコード ロジックを検出します。
ドライバー検証ツールのデッドロック検出オプションと !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 の使用を監視したり、所有されていないリソースの使用を監視したりすることはありません。
デッドロック検出の効果
ドライバー検証ツールのデッドロック検出ルーチンは、必ずしも同時ではないロック階層違反を検出します。 ほとんどの場合、これらの違反は、その機会が与えられたときにデッドロックするコード パスを特定します。
潜在的なデッドロックを見つけるために、ドライバー検証ツールは、リソースの獲得順序のグラフを構築し、ループをチェックします。 リソースごとにノードを作成し、あるロックが別のロックの前に取得されるたびに矢印を描画する場合、パス ループはロック階層違反を表します。
ドライバー検証ツールは、これらの違反のいずれかが検出されたときにバグ チェックを発行します。 これは、実際のデッドロックが発生する前に行われます。
Note
競合するコード パスが同時に発生することは決してない場合でも、ロック階層違反が発生した場合は、それらのパスを書き換える必要があります。 このようなコードは「デッドロックが起こるのを待っている」状態であり、コードを少し書き換えただけで、本当のデッドロックを引き起こす可能性があります。
デッドロック検出で違反が検出されると、バグ チェック 0xC4が発行されます。 このバグ チェックの最初のパラメーターは、正確に違反を示します。 違反の可能性は以下の通りです。
ロック階層違反に関係する 2 つ以上のスレッド
既に共有所有者であるリソースを排他的に取得しようとするスレッド (排他的に所有されているリソースは共有を取得できますが、共有リソースを排他的には取得できません)。
同じリソースを 2 回取得しようとするスレッド (自己デッドロック)
最初に取得されずに解放されたリソース
取得したスレッドとは異なるスレッドによって解放されるリソース
複数回初期化されたリソース、またはまったく初期化されていないリソース
リソースを所有したまま削除されるスレッド
Windows 7 以降、ドライバー検証ツールは、発生する可能性のあるデッドロックを予測できます。 たとえば、同じKSPIN_LOCKデータ構造を通常のスピン ロックとスタック キュースピン ロックの両方として使用しようとしています。
バグ チェック パラメータのリストについては、バグ チェック 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION) を参照してください。
デッドロック検出の監視
デッドロック検出で違反が検出されると、!deadlock カーネル デバッガー拡張機能を 使用して、発生した内容を正確に調査できます。 ロック階層トポロジと、ロックが最初に取得された時点の各スレッドの呼び出し履歴を表示できます。
詳細な !デッドロック 拡張機能の例とデバッガー拡張機能に関する一般的な情報については、Windows 用デバッグ ツール パッケージのドキュメントを参照してください。 詳細については、「Windows のデバッグ」を参照してください。
このオプションのアクティブ化
Note
このオプションは、カーネル同期遅延ファジーと 互換性がありません
Driver Verifier Manager または 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
ドライバー検証マネージャーの使用
[カスタム設定の作成 (コード開発者用)] を選択し、 [次へ]をクリックします。
選択 全リストから [個々の設定を選択] を選択します。
(チェック) デッドロック検出を選択します。
デッドロック検出機能は標準設定にも含まれています。 この機能を使用するには、 ドライバー検証ツール マネージャーで、, [標準設定の作成]を選択します。