我是一名支持工程师,在失败过程的转储中,我看到有一些锁。
使用Windbg(Visual Studio无法正确处理调用堆栈)我发现一个函数(ClassName::F()
)正在回来。该函数使用一个关键部分,并调用一个子函数(ClassName::f_sub()
),简而言之,他正在调用相同的关键部分:
int ClassName::f_sub(){
EnterCriticalSection(&m_cs);
...
LeaveCriticalSection(&m_cs);
return ...;
}
int ClassName::F() {
EnterCriticalSection(&m_cs);
...
int temp = f_sub();
...
LeaveCriticalSection(&m_cs);
return ...;
}
每次使用相同的关键部分m_cs
(ClassName
的财产)。
在我看来,这使得以下顺序成为可能:
Thread 1 : F() : Enter the critical section. (Thread 1 is in)
Thread 1 : f_sub() : Enter the critical section. (Thread 1 is in)
Thread 1 : f_sub() : Leave the critical section. (Thread 1 is out)
Thread 2 : F() : Enter the critical section. (Thread 2 is in)
=> WRONG! Thread 2 should be forced to wait for Thread 1 leaving the critical section via F().
我的分析是否正确,这是否意味着建议对主要和子功能使用不同的关键部分?
我的分析是否正确,这是否意味着建议对主要和子功能使用不同的关键部分?
来自Microsoft Docs(强调我的):
在线程拥有关键部分的所有权后,它可以对EnterCriticalSection或TryEnterCriticalSection进行额外调用,而不会阻止其执行。这可以防止线程在等待它已经拥有的关键部分时自行死锁。每次EnterCriticalSection和TryEnterCriticalSection成功时,线程都会进入临界区。每次进入临界区时,线程必须调用一次LeaveCriticalSection。
所以不,你所描述的不应该发生。完全可以多次进入临界区,并且需要完全保留多次。