私は自分のプログラムでデッドロックの可能性を探していますが、次のことを疑っています。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()またはその親戚のいずれかが関与します。