2012-01-12 15 views
6

我遇到了C++中关键部分的问题。我得到一个悬窗,当我倾倒的过程中,我可以看到线程等待一个关键部分:为什么我的线程被某个关键部分阻塞而不被任何东西占用?

16 Id: b10.b88 Suspend: 1 Teb: 7ffae000 Unfrozen 
ChildEBP RetAddr 
0470f158 7c90df3c ntdll!KiFastSystemCallRet 
0470f15c 7c91b22b ntdll!NtWaitForSingleObject+0xc 
0470f1e4 7c901046 ntdll!RtlpWaitForCriticalSection+0x132 
0470f1ec 0415647e ntdll!RtlEnterCriticalSection+0x46 

行数据等,都表示进入某个特定的关键部分。唯一的问题是,没有其他线程似乎打开这个关键部分。 Windbg's!locks命令没有显示任何内容,并且转储临界区域表明它没有锁定,如下面结构中的null owner和-1 LockCount所示。

0:016> dt _RTL_CRITICAL_SECTION 42c2318 
_RTL_CRITICAL_SECTION 
    +0x000 DebugInfo  : 0x02c8b318 _RTL_CRITICAL_SECTION_DEBUG 
    +0x004 LockCount  : -1 
    +0x008 RecursionCount : -1 
    +0x00c OwningThread  : (null) 
    +0x010 LockSemaphore : 0x00000340 
    +0x014 SpinCount  : 0 

0:016> dt _RTL_CRITICAL_SECTION_DEBUG 2c8b318 
_RTL_CRITICAL_SECTION_DEBUG 
    +0x000 Type    : 0 
    +0x002 CreatorBackTraceIndex : 0x2911 
    +0x004 CriticalSection : 0x042c2318 _RTL_CRITICAL_SECTION 
    +0x008 ProcessLocksList : _LIST_ENTRY [ 0x2c8b358 - 0x2c8b2e8 ] 
    +0x010 EntryCount  : 1 
    +0x014 ContentionCount : 1 
    +0x018 Flags   : 0xbaadf00d 
    +0x01c CreatorBackTraceIndexHigh : 0xf00d 
    +0x01e SpareWORD  : 0xbaad 

这怎么可能?即使在另一个线程尚未调用LeaveCriticalSection的死锁中,我也希望看到关键部分本身被标记为锁定。有没有人有任何调试建议或可能的修复?

+1

有一件事我会检查是我是否做了一个EnterCriticalSection的后跟2个LeaveCriticalSections。 – Naveen 2012-01-12 04:23:43

+0

检查关键部分是否未被删除。从[DeleteCriticalSection](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682552%28v=vs.85%29.aspx):如果临时部分仍然拥有时被删除,等待已删除关键部分的所有权的线程的状态是未定义的。 – hmjd 2012-01-12 08:49:12

+0

@hmjd可能是正确的0xbaadf00d mead,执行释放。 – Zuljin 2012-01-12 18:19:51

回答

8

它原来是一个其中LeaveCriticalSection物被称为不具有相应EnterCriticalSection的错误。这引起了关键节递减锁定计数和RecursionCount成以下状态(锁定计数的缺省值是-1和RecursionCount是0):

0:016> dt _RTL_CRITICAL_SECTION 1092318 
_RTL_CRITICAL_SECTION 
    +0x000 DebugInfo  : 0x....... _RTL_CRITICAL_SECTION_DEBUG 
    +0x004 LockCount  : -2 
    +0x008 RecursionCount : -1 
    +0x00c OwningThread  : (null) 
    +0x010 LockSemaphore : 0x....... 
    +0x014 SpinCount  : 0 

当进行随后的EnterCriticalSection的,它挂因为RecursionCount是非零 - 如果RecursionCount为0,则线程只能获得关键部分的所有权。但是,它确实增加了LockCount(将其回到我在原始问题中看到的-1),只是为了混淆事项。

总之,如果你看到一个关键部分用LockCount和递归计数-1来锁定你的线程,这意味着存在过度的解锁。

至于代码使其:

if (SysStringLen(bstrState) > 0) 
    CHECKHR_CS(m_pStateManager->SetState(bstrState), &m_csStateManagerLock); 

和错误检查宏的定义:

#define CHECKHR_CS(x, cs)      \ 
    EnterCriticalSection(cs);      \ 
    if(FAILED(hr = (x))) {      \ 
     LeaveCriticalSection(cs);     \ 
     return hr;       \ 
    }       \ 
    LeaveCriticalSection(cs); 

宏缺少它的内容周围大括号,所以if语句不满意只能跳过EnterCriticalSection。显然是一个问题。

+3

考虑使用[在RAII成语](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)和包裹'EnterCriticalSection的()'在一个构造函数和''LeaveCriticalSection在析构函数()。这样你就不会忘记解锁互斥锁(或解锁两次)。这是[Boost's'lock_guard'](http://www.boost.org/doc/libs/1_48_0/doc/html/thread/synchronization.html#thread.synchronization.locks.lock_guard)的工作原理。 – 2012-01-13 05:03:39

+0

好点。如果这里使用了未声明的变量,它会抛出一个编译器错误。 – dlanod 2012-01-13 05:11:06

相关问题