void * MultiLockRandomSafeThread( void * p ) { const unsigned int value = reinterpret_cast< unsigned int >( p ); unsigned int testCount = 0; unsigned int failCount = 0; volatile Thing * thing = nullptr; Thing::ThingPool pool; LevelMutexInfo::MutexContainer mutexes; mutexes.reserve( thingCount ); unsigned int jj = 0; unsigned int place = 0; try { for ( unsigned int ii = 0; ii < thingCount; ++ii ) { pool.clear(); pool.reserve( thingCount ); for ( place = 0; place < thingCount; ++place ) { place += ::rand() % 3; if ( thingCount <= place ) break; thing = Thing::GetFromPool( place ); assert( nullptr != thing ); pool.push_back( thing ); } const unsigned int poolCount = pool.size(); mutexes.clear(); for ( jj = 0; jj < poolCount; ++jj ) { thing = pool[ jj ]; assert( nullptr != thing ); mutexes.push_back( &thing->GetMutex() ); } MultiMutexLocker locker( mutexes ); (void)locker; for ( jj = 0; jj < poolCount; ++jj ) { thing = pool[ jj ]; assert( nullptr != thing ); thing->SetValue( value ); } ::GoToSleep( 3 ); for ( jj = 0; jj < poolCount; ++jj ) { thing = pool[ jj ]; assert( nullptr != thing ); if ( thing->GetValue() != value ) failCount++; testCount++; } } } catch ( ... ) { assert( false ); } TestResults::GetIt()->SetResult( value, testCount, failCount ); return nullptr; }
void SingleThreadComplexMultiLockTest( bool doSetup ) { ::srand( static_cast< unsigned int >( time( nullptr ) ) ); if ( doSetup ) { Thing::MakePool( thingCount ); } const unsigned int priorLevel = GetCurrentThreadsLevel(); const unsigned int priorLockCount = CountLocksInCurrentThread(); const unsigned int priorMutexCount = CountMutexesInCurrentThread(); const unsigned int priorLevelMutexCount = CountMutexesAtCurrentLevel(); if ( LevelMutexInfo::UnlockedLevel == priorLevel ) { assert( priorLockCount == 0 ); assert( priorMutexCount == 0 ); assert( priorLevelMutexCount == 0 ); } else { assert( priorLockCount != 0 ); assert( priorMutexCount != 0 ); assert( priorLevelMutexCount != 0 ); assert( priorLevelMutexCount <= priorMutexCount ); assert( priorMutexCount <= priorLockCount ); } volatile Thing * thing0 = Thing::GetFromPool( 0 ); volatile Thing * thing1 = Thing::GetFromPool( 1 ); volatile Thing * thing2 = Thing::GetFromPool( 2 ); volatile Thing * thing3 = Thing::GetFromPool( 3 ); volatile Thing * thing4 = Thing::GetFromPool( 4 ); volatile Thing * thing5 = Thing::GetFromPool( 5 ); volatile Thing * thing6 = Thing::GetFromPool( 6 ); volatile Thing * thing7 = Thing::GetFromPool( 7 ); assert( nullptr != thing0 ); assert( nullptr != thing1 ); assert( nullptr != thing2 ); assert( nullptr != thing3 ); assert( nullptr != thing4 ); assert( nullptr != thing5 ); assert( nullptr != thing6 ); assert( nullptr != thing7 ); LevelMutexInfo::MutexContainer mutexes; mutexes.reserve( thingCount ); MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes ); assert( result == MutexErrors::EmptyContainer ); mutexes.push_back( &thing0->GetMutex() ); mutexes.push_back( &thing1->GetMutex() ); mutexes.push_back( &thing2->GetMutex() ); mutexes.push_back( &thing3->GetMutex() ); mutexes.push_back( &thing4->GetMutex() ); mutexes.push_back( &thing5->GetMutex() ); mutexes.push_back( &thing6->GetMutex() ); mutexes.push_back( &thing7->GetMutex() ); result = LevelMutexInfo::MultiLock( mutexes ); assert( result == MutexErrors::Success ); assert( GetCurrentThreadsLevel() == thing0->GetMutex().GetLevel() ); assert( CountLocksInCurrentThread() == priorLockCount + thingCount ); result = LevelMutexInfo::MultiUnlock( mutexes ); assert( result == MutexErrors::Success ); assert( GetCurrentThreadsLevel() == priorLevel ); assert( CountLocksInCurrentThread() == priorLockCount ); assert( CountMutexesInCurrentThread() == priorMutexCount ); assert( CountMutexesAtCurrentLevel() == priorLevelMutexCount ); mutexes.clear(); mutexes.push_back( &thing7->GetMutex() ); mutexes.push_back( &thing6->GetMutex() ); mutexes.push_back( &thing5->GetMutex() ); mutexes.push_back( &thing4->GetMutex() ); mutexes.push_back( &thing3->GetMutex() ); mutexes.push_back( &thing2->GetMutex() ); mutexes.push_back( &thing1->GetMutex() ); mutexes.push_back( &thing0->GetMutex() ); result = LevelMutexInfo::MultiLock( mutexes ); assert( result == MutexErrors::Success ); assert( GetCurrentThreadsLevel() == thing0->GetMutex().GetLevel() ); assert( CountLocksInCurrentThread() == priorLockCount + thingCount ); result = LevelMutexInfo::MultiUnlock( mutexes ); assert( result == MutexErrors::Success ); assert( GetCurrentThreadsLevel() == priorLevel ); assert( CountLocksInCurrentThread() == priorLockCount ); assert( CountMutexesInCurrentThread() == priorMutexCount ); assert( CountMutexesAtCurrentLevel() == priorLevelMutexCount ); RandomizeMutexOrder( mutexes ); result = LevelMutexInfo::MultiLock( mutexes ); assert( result == MutexErrors::Success ); assert( GetCurrentThreadsLevel() == thing0->GetMutex().GetLevel() ); assert( CountLocksInCurrentThread() == priorLockCount + thingCount ); result = LevelMutexInfo::MultiUnlock( mutexes ); assert( result == MutexErrors::Success ); assert( GetCurrentThreadsLevel() == priorLevel ); assert( CountLocksInCurrentThread() == priorLockCount ); assert( CountMutexesInCurrentThread() == priorMutexCount ); assert( CountMutexesAtCurrentLevel() == priorLevelMutexCount ); if ( doSetup ) Thing::DestroyPool(); }