2012-01-12 21 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の!locksコマンドで何も表示されず、クリティカルセクションをダンプすると、ヌルの所有者が見ることができるようにロックされていないことと、以下の構造の-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

私がチェックすることの1つは、1つのEnterCriticalSectionに2つのLeaveCriticalSectionsを続けたかどうかです。 – Naveen

+0

クリティカルセクションが削除されていないことを確認します。 [DeleteCriticalSection](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682552%28v=vs.85%29.aspx):クリティカルセクションがまだ所有されているときに削除された場合、削除されたクリティカルセクションの所有権を待機しているスレッドの状態は未定義です。 – hmjd

+0

@hmjdはおそらく、割り当て解除が実行された正しい0xbaadf00d meadです。 – Zuljin

答えて

8

LeaveCriticalSectionが対応するEnterCriticalSectionなしで呼び出されていたバグが判明しました。これは、(LOCKCOUNTのデフォルトは-1とRecursionCountが0である)、クリティカルセクションは、次の状態にLOCKCOUNT及びRecursionCountを減少させる:後続EnterCriticalSectionが実行されたときRecursionCountが非ゼロであったため

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 

、それがハング - スレッドは、RecursionCountが0の場合にのみ、クリティカルセクションの所有権を取得することができます。ただし、問題を混乱させるためにLockCountを増やしています(元の質問の-1に戻します)。

要約すると、LockCountとRecursionCountの両方が-1のスレッドを停止するクリティカルセクションが表示された場合は、過剰なロック解除が行われたことを意味します。

コードを引き起こしに関して:マクロは、その内容の周りの中括弧が欠けているので、if文ではない

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

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

そして、エラーチェックマクロの定義満足しているのはEnterCriticalSectionだけです。明らかに問題。

+3

[RAIIイディオム](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)を使用し、コンストラクタで 'EnterCriticalSection()'を、デストラクタで 'LeaveCriticalSection()'をラップすることを検討してください。そうすれば、ミューテックスのロックを解除する(またはロックを2回解除する)のを忘れることはありません。これは[Boostの 'lock_guard'](http://www.boost.org/doc/libs/1_48_0/doc/html/thread/synchronization.html#thread.synchronization.locks.lock_guard)の仕組みです。 –

+0

良い点。宣言されていない変数がここで使用されていた場合、コンパイルエラーがスローされました。 – dlanod

関連する問題