B
In einem anderen Forum hatte jemand eine gute Idee für einen Workaround: einfach für beide Thread-Typen zusätzlich auf ein immer gesetztes manual-reset Event warten lassen, im einen Fall wird dann natürlich aus einem WaitForSingleObject ein WaitForMultipleObjects. So funktioniert das und der Haupt-Thread bekommt auch CPU-Zeit und hungert nicht aus.
So sieht der Test-Code jetzt aus:
#include <windows.h>
#include <cstdio>
#include <unordered_map>
HANDLE hEvt,
hSema,
hEvtAlwaysSet;
bool volatile fReleased;
DWORD WINAPI LockAndReleaseThread( LPVOID lpvThreadParam );
int main()
{
int const NTHREADS = 2;
HANDLE ahWait[3];
ahWait[0] = ::hEvt = CreateEvent( NULL, FALSE, TRUE, NULL );
ahWait[1] = ::hSema = CreateSemaphore( NULL, 0, 1, NULL );
ahWait[2] = ::hEvtAlwaysSet = CreateEvent( NULL, TRUE, TRUE, NULL );
fReleased = false;
for( int i = 0; i < NTHREADS; i++ )
CreateThread( NULL, 0, LockAndReleaseThread, NULL, 0, NULL );
for( ; ; )
WaitForMultipleObjects( 3, ahWait, TRUE, INFINITE ),
std::printf( "main thread is holding lock and received signal\n" ),
::fReleased = false,
SetEvent( ::hEvt );
return 0;
}
char GetID();
DWORD WINAPI LockAndReleaseThread( LPVOID lpvThreadParam )
{
HANDLE ahWait[2] = { ::hEvt, ::hEvtAlwaysSet };
for( ; ; )
{
WaitForMultipleObjects( 2, ahWait, TRUE, INFINITE );
std::printf( "spawned thread with id %c is holding lock\n", (char)GetID() );
if( !::fReleased )
ReleaseSemaphore( ::hSema, 1, NULL ),
::fReleased = true;
Sleep( 1000 );
SetEvent( ::hEvt );
}
return 0;
}
char GetID()
{
static std::unordered_map<DWORD, char> mapTIDsToIDs;
static char nextId = 'A';
DWORD dwThreadId;
if( mapTIDsToIDs.find( dwThreadId = GetCurrentThreadId() ) == mapTIDsToIDs.end() )
return mapTIDsToIDs[dwThreadId] = nextId++;
else
return mapTIDsToIDs[dwThreadId];
}