我在我的程序中寻找可能的死锁并且我怀疑以下内容。 如果两个线程同时调用EnterCriticalSection并且线程#1在进入后立即调用DeleteCriticalSection会发生什么情况,那么仍然在EnterCriticalSection调用中的线程#2会发生什么?
感谢。
答案 0 :(得分:12)
如果两个线程同时调用EnterCriticalSection会发生什么 和线程#1在输入后立即调用DeleteCriticalSection,什么 发生在仍然在EnterCriticalSection调用中的线程#2?
两个线程无法同时进入临界区。那会破坏关键部分的目的。线程#1首先进入临界区,或者线程#2首先进入临界区。你可以在这里玩两种可能的交错。
让我们说交错是这样的:
Thread 1 Thread 2 -------- -------- | | | | EnterCS() | Lock Taken | | | | EnterCS() | Blocked | | | | DeleteCS() | | | | ??? | ...
在这种情况下,线程#2的状态为undefined according to MSDN:
DeleteCriticalSection函数
<强>说明强>
删除关键部分对象会释放所有系统 对象使用的资源。
删除关键部分对象后,请勿引用 任何在关键部分上运行的函数中的对象(例如 EnterCriticalSection,TryEnterCriticalSection和 LeaveCriticalSection除了InitializeCriticalSection和 InitializeCriticalSectionAndSpinCount。如果你试图这样做,记忆 可能会发生腐败和其他意外错误。
如果临界区在仍然拥有时被删除,则线程的状态 等待已删除的关键部分的所有权未定义。
因此,如果你的两个线程遇到上述交错是不够的,那么操作系统会给你无保证你的程序将继续按预期工作。例如,这可能包括死锁线程#2。
但如果交错是这样的:
Thread 1 Thread 2 -------- -------- | | | | | EnterCS() | Lock Taken | | EnterCS() | Blocked | | | | | | ExitCS() | Lock Released | | Unblocked | LockTaken | | | DeleteCS() | | | | | ... ...
然后很明显,由于线程#1被阻止,它无法删除临界区,直到线程#2离开临界区。然后假设没有其他线程进入临界区,线程#1将能够毫无问题地删除它。
您提出的方案基本上是竞争条件。根据线程的时间安排,它可能正常工作或导致不可预测的问题。在这种情况下,您必须重新构建代码,以便在所有感兴趣的线程释放临界区之后发生对关键部分的破坏。
在这个双线程场景中,一种解决方法是让线程#1离开临界区并等待所有其他线程先完成,然后再删除临界区。像这样的东西,例如:
// Pseudocode for exposition
void Thread1()
{
EnterCS();
// Do stuff
ExitCS();
WaitForThread2();
DeleteCS();
}
void Thread2()
{
EnterCS();
// Do stuff
ExitCS();
}
现在,两种可能的交错看起来像这样:
Thread #2 acquires lock first: . Thread #1 acquires lock first: . Thread 1 Thread 2 . Thread 1 Thread 2 -------- -------- . -------- -------- | | . | | | EnterCS() . EnterCS() | | Lock Taken . Lock Taken | | | . | | EnterCS() | . // Do stuff EnterCS() Blocked // Do stuff . | Blocked | | . | | | | . ExitCS() | | ExitCS() . Lock Released | | Lock Released . | | | | . | Unblocked Unblocked | . | Lock Taken Lock Taken | . | | | | . | // Do stuff // Do stuff | . | | | | . | ExitCs() ExitCS() | . | Lock Released Lock Released | . | | | | . | | | | . | | WaitForThread2() --+ . WaitForThread2() --+ | . | DeleteCS() . DeleteCS() | . | | . | done . done
WaitForThread2()
的确切实施取决于您的计划的性质,但肯定会涉及WaitForSingleObject()
或其任何一位亲属。