【发布时间】:2011-08-19 15:18:58
【问题描述】:
我的程序在一个我可以重现的小场景中随机崩溃,但它发生在来自 ntdll.dll 的 mlock.c(这是一个 VC++ 运行时文件)中,我看不到堆栈跟踪。不过,我确实知道它发生在我的一个线程函数中。
这是程序崩溃的mlock.c代码:
void __cdecl _unlock (
int locknum
)
{
/*
* leave the critical section.
*/
LeaveCriticalSection( _locktable[locknum].lock );
}
错误是“指定的句柄无效”。如果我查看 locknum,它是一个大于 _locktable 大小的数字,所以这是有道理的。
这似乎与关键部分的使用有关。我确实在我的线程中使用了 CRITICAL_SECTIONS,通过 CCriticalSection 包装类及其关联的 RAII 保护 CGuard。两个here 的定义以避免更加混乱。
这是崩溃的线程函数:
unsigned int __stdcall CPlayBack::timerThread( void * pParams ) {
#ifdef _DEBUG
DRA::CommonCpp::SetThreadName( -1, "CPlayBack::timerThread" );
#endif
CPlayBack * pThis = static_cast<CPlayBack*>( 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<DWORD>( 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;
}
有人遇到过这种错误吗?有什么建议吗?
编辑:我看到了一些调用堆栈:调用来自 ~CSharedMemory。所以那里一定有一些竞争条件
编辑:更多CSharedMemory代码here
【问题讨论】:
-
这两个类本身看起来不错。你能展示一些与你如何使用它们有关的代码吗?您确定在使用之前正确调用了构造函数(构造函数上没有线程争用吗?)。它们是否被动态分配(出于某种原因)?
-
您的课程与 CRT 代码没有任何关系,它使用的是 Windows。调试线程竞争和堆损坏从来都不是一件有趣的事情,祝你好运。
-
@Chad:我编辑了我的问题。我发布了在崩溃的线程中使用 CCriticalSections 的方式
-
我在看到您的编辑之前发布了我的回复。
-
关于您的编辑,我想到了一点。关键部分和一般同步用于保护数据,而不是代码。您的
m_csAccessUse对象对我来说似乎是多余的。
标签: c++ windows multithreading visual-c++ critical-section