Моя программа случайно дает сбой в небольшом сценарии, который я могу воспроизвести, но это происходит в mlock.c (который является файлом времени выполнения VC ++) из ntdll.dll, и я не могу увидеть трассировку стека. Однако я знаю, что это происходит в одной из моих потоковых функций.
Это код mlock.c, в котором происходит сбой программы:
void __cdecl _unlock (
int locknum
)
{
/*
* leave the critical section.
*/
LeaveCriticalSection( _locktable[locknum].lock );
}
Ошибка: «Указан неверный дескриптор». Если я посмотрю на locknum, это число больше, чем размер _locktable, так что в этом есть некоторый смысл.
Похоже, это связано с использованием Critical Section. Я использую CRITICAL_SECTIONS в своем потоке через класс-оболочку CCriticalSection и связанный с ним защиту RAII, CGuard. Определения для обоих здесь , чтобы избежать еще большего беспорядка.
Это функция потока, которая дает сбой:
unsigned int __stdcall CPlayBack::timerThread( void * pParams ) {
#ifdef _DEBUG
DRA::CommonCpp::SetThreadName( -1, "CPlayBack::timerThread" );
#endif
CPlayBack * pThis = static_cast( pParams );
bool bContinue = true;
while( bContinue ) {
float m_fActualFrameRate = pThis->m_fFrameRate * pThis->m_fFrameRateMultiplier;
if( m_fActualFrameRate != 0 && pThis->m_bIsPlaying ) {
bContinue = ( ::WaitForSingleObject( pThis->m_hEndThreadEvent, static_cast( 1000.0f / m_fActualFrameRate ) ) == WAIT_TIMEOUT );
CImage img;
if( pThis->m_bIsPlaying && pThis->nextFrame( img ) )
pThis->sendImage( img );
}
else
bContinue = ( ::WaitForSingleObject( pThis->m_hEndThreadEvent, 10 ) == WAIT_TIMEOUT );
}
::GetErrorLoggerInstance()->Log( LOG_TYPE_NOTE, "CPlayBack", "timerThread", "Exiting thread" );
return 0;
}
Откуда тут CCriticalSection
? Каждый объект CImage
содержит объект CCriticalSection
, который он использует посредством блокировки CGuard
RAII. Более того, каждый CImage
содержит объект CSharedMemory
, который реализует подсчет ссылок. С этой целью он также содержит два CCriticalSection
, один для данных и один для счетчика ссылок. Хороший пример такого взаимодействия лучше всего можно увидеть в деструкторах:
CImage::~CImage() {
CGuard guard(m_csData);
if( m_pSharedMemory != NULL ) {
m_pSharedMemory->decrementUse();
if( !m_pSharedMemory->isBeingUsed() ){
delete m_pSharedMemory;
m_pSharedMemory = NULL;
}
}
m_cProperties.ClearMin();
m_cProperties.ClearMax();
m_cProperties.ClearMode();
}
CSharedMemory::~CSharedMemory() {
CGuard guardUse( m_cs );
if( m_pData && m_bCanDelete ){
delete []m_pData;
}
m_use = 0;
m_pData = NULL;
}
Кто-нибудь сталкивался с такого рода ошибкой? Есть предложения?
Edit : Мне нужно увидеть стек вызовов: вызов поступает из ~ CSharedMemory. Так что там должно быть какое-то состояние гонки
Правка : Подробнее код CSharedMemory здесь