Почему мой поток заблокирован критическим разделом, который ничем не удерживается?

у меня проблема с критическим разделом в 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

данные по линии, etc, все показывают вход в специфический критический раздел. Единственная проблема заключается в том, что никакие другие потоки не держат этот критический раздел открытым. Там ничего не указано Windbg !команда locks и сброс критического раздела указывает, что он не заблокирован, как видно из владелец null и -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 ответов


это оказалось ошибкой, когда LeaveCriticalSection вызывался без соответствующего EnterCriticalSection. Это привело к тому, что критический раздел уменьшил LockCount и RecursionCount до следующего состояния (по умолчанию для LockCount -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, так и с RecursionCount -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);

макрос не имеет фигурных скобок вокруг его содержимого, поэтому если оператор не удовлетворен, только пропускает EnterCriticalSection. Очевидно, проблема.