偶然发现Windows API函数LeaveCriticalSection存在一个问题,那就是在调用它离开临界区时,会把临界区引用计数减一,而不判断当前线程是不是拥有该临界区,这样就可能引发问题,比如A线程拥有该临界区,但B线程可以调用LeaveCriticalSection来使得其它等待该临界区的线程拥有该临界区,或者调用LeaveCriticalSection次数大于EnterCriticalSection的次数也可能出现误操作而导致不可预知的后果。
把EnterCriticalSection换下面这一段代码可以有效的防止占用锁的线程已经退出而导致死锁的情况(亲测有效):
//尝试进入临界区
while(!TryEnterCriticalSection(&aoSection)){
//进入失败,判断当前占有临界区的线程是否还存活
if(aoSection.RecursionCount > 0){
DWORD result = WaitForSingleObject(aoSection.OwningThread, 0);
if(result == WAIT_FAILED){
//如果线程已经退出,则代表线程被异常结束或代码问题导致锁没有释放,就利用此bug强制释放锁
long lRecursionCount = aoSection.RecursionCount;
for(int i = 0; i < lRecursionCount; i++){
LeaveCriticalSection(&moSection);
}
}
}
}
网友评论