私は自分のプログラムでデッドロックの可能性を探していますが、次のことを疑っています。2 つのスレッドが同時に EnterCriticalSection を呼び出し、スレッド #1 が入った直後に DeleteCriticalSection を呼び出した場合、まだ EnterCriticalSection 呼び出しにあるスレッド #2 はどうなりますか?
ありがとう。
私は自分のプログラムでデッドロックの可能性を探していますが、次のことを疑っています。2 つのスレッドが同時に EnterCriticalSection を呼び出し、スレッド #1 が入った直後に DeleteCriticalSection を呼び出した場合、まだ EnterCriticalSection 呼び出しにあるスレッド #2 はどうなりますか?
ありがとう。
2 つのスレッドが同時に EnterCriticalSection を呼び出し、スレッド #1 が入った直後に DeleteCriticalSection を呼び出した場合、まだ EnterCriticalSection 呼び出しにあるスレッド #2 はどうなりますか?
2 つのスレッドが同時にクリティカル セクションに入ることができません。それは、クリティカル セクションの目的を無効にします。スレッド #1 が最初にクリティカル セクションに入るか、スレッド #2 が最初にクリティカル セクションに入ります。ここでは、2 つのインターリーブが可能です。
インターリーブがこれであるとしましょう:
スレッド 1 スレッド 2 -------- -------- | | | | | | | | EnterCS() | ロックが取られました | | | | | | | EnterCS() | | ブロックされた | | | | | | | | 削除CS() | | | | | | | ??? | | ...
この場合、 MSDN によると、スレッド #2 の状態は未定義です。
DeleteCriticalSection 関数
備考
クリティカル セクション オブジェクトを削除すると、そのオブジェクトが使用していたすべてのシステム リソースが解放されます。
クリティカル セクション オブジェクトが削除された後は、InitializeCriticalSection と InitializeCriticalSectionAndSpinCount 以外のクリティカル セクション (EnterCriticalSection、TryEnterCriticalSection、LeaveCriticalSection など) で動作する関数でオブジェクトを参照しないでください。そうしようとすると、メモリの破損やその他の予期しないエラーが発生する可能性があります。
クリティカル セクションが所有されている間に削除された場合、削除されたクリティカル セクションの所有権を待機しているスレッドの状態は未定義です。
したがって、2 つのスレッドが上記のインターリーブに遭遇するほど不運だった場合、オペレーティング システムは、プログラムが期待どおりに動作し続けることを保証しません。これには、たとえばスレッド #2 のデッドロックが含まれる場合があります。
しかし、インターリーブが次の場合:
スレッド 1 スレッド 2 -------- -------- | | | | | | | | | | EnterCS() | | ロックが取られました | | | | EnterCS() | ブロックされました | | | | | | | | | | | ExitCS() | | ロック解除 | | | | ブロック解除 | ロックテイクン | | | | | 削除CS() | | | | | | | | | ... ... ...
次に、明らかに、スレッド #1 がブロックされているため、スレッド #2 がクリティカル セクションを離れるまで、クリティカル セクションを削除できません。次に、他のスレッドがクリティカル セクションに入らないと仮定すると、スレッド #1 は問題なく削除できます。
あなたが提案するシナリオは、本質的に競合状態です。スレッドのタイミングによっては、問題なく動作するか、予期しない問題が発生する可能性があります。この場合、関連するすべてのスレッドがクリティカル セクションを解放した後にクリティカル セクションが破棄されるように、コードを再構築する必要があります。
この 2 スレッドのシナリオで、これを修正する 1 つの方法は、クリティカル セクションを削除する前に、スレッド #1 をクリティカル セクションから離れさせ、他のすべてのスレッドが最初に終了するのを待つことです。たとえば、次のようなものです。
// Pseudocode for exposition
void Thread1()
{
EnterCS();
// Do stuff
ExitCS();
WaitForThread2();
DeleteCS();
}
void Thread2()
{
EnterCS();
// Do stuff
ExitCS();
}
ここで、考えられる 2 つのインターリーブは次のようになります。
スレッド #2 が最初にロックを取得します: . スレッド #1 が最初にロックを取得します。 . スレッド 1 スレッド 2 。スレッド 1 スレッド 2 -------- -------- . -------- -------- | | | | . | | | | | | CS() を入力します。EnterCS() | | | ロックがかかりました。ロックが取られました | | | | | . | | | | EnterCS() | . // 処理を行う EnterCS() ブロックされた // 何かを行う . | | ブロックされた | | | | . | | | | | | | | . ExitCS() | | | ExitCS() . ロック解除 | | | ロックが解除されました。| | | | | | | | . | | ブロック解除 ブロック解除 | . | | ロックが取られました ロックが取られました | . | | | | | | | | . | | // 何かをする // 何かをする | . | | | | | | | | . | | ExitCs() ExitCS() | . | | ロック解除 ロック解除 | . | | | | | | | | . | | | | | | | | . | | | | WaitForThread2() --+ . WaitForThread2() --+ | | . | | CS() を削除します。削除CS() | | . | | | | . | | 終わり 。終わり
の正確な実装WaitForThread2()
は、プログラムの性質によって異なりますが、確実にWaitForSingleObject()
またはその親戚のいずれかが関与します。