私のプログラムは、再現できる小さなシナリオでランダムにクラッシュしますが、ntdll.dll の mlock.c (VC++ ランタイム ファイル) で発生し、スタック トレースが表示されません。ただし、スレッド関数の1つで発生することは知っています。
これは、プログラムがクラッシュする mlock.c コードです。
void __cdecl _unlock (
int locknum
)
{
/*
* leave the critical section.
*/
LeaveCriticalSection( _locktable[locknum].lock );
}
エラーは「無効なハンドルが指定されました」です。locknum を見ると、_locktable のサイズよりも大きい数値なので、これはある程度理にかなっています。
これは、クリティカル セクションの使用法に関連しているようです。CCriticalSection ラッパー クラスとそれに関連する RAII ガードである CGuard を介して、スレッドで CRITICAL_SECTIONS を使用しています。さらに混乱を避けるために、両方の定義をここに示します。
これはクラッシュしているスレッド関数です:
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
くる?すべてのオブジェクトには、 RAII ロックを介して使用するCImage
オブジェクトが含まれています。さらに、everyには、参照カウントを実装するオブジェクトが含まれています。そのために、2 つの も含まれています。1 つはデータ用で、もう 1 つは参照カウンター用です。これらの相互作用の良い例は、デストラクタで最もよく見られます。CCriticalSection
CGuard
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コードの詳細はこちら