2012-01-12 13 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

相關問題