We can use either the new condition variable primitive or windows event in order to synchronize threads in WinNT v6.x or later. Consider the following two approaches, we want workers to run at the same time when "go" is set in main, otherwise they should all block.
/*language C code*/
/*Windows Condition Variable*/
int go=0;
CONDITION_VARIABLE cv;
SRWLOCK lock;
void workers()
{
AcquireSRWLockShared(&lock);
if(go==0)
{
SleepConditionVariableSRW(&cv, &lock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
}
ReleaseSRWLockShared(&lock);
/*
Workers continue...
*/
}
void main()
{
int i;
InitializeConditionVariable(&cv);
InitializeSRWLock(&lock);
for(i=0;i<10;i++)
{
CreateThread(0, 0, workers, 0, 0, 0);
}
AcquireSRWLockExclusive(&lock);
go=1;
ReleaseSRWLockExclusive(&lock);
WakeAllConditionVariable(&cv);
}
or
/*language C code*/
/*Windows Event*/
HANDLE go;
void workers()
{
WaitForSingleObject(go, INFINITE);
/*
Workers continue...
*/
}
void main()
{
int i;
go=CreateEvent(0,1,0,0); /*No security descriptor, Manual Reset, initially 0, no name*/
for(i=0;i<10;i++)
{
CreateThread(0, 0, workers, 0, 0, 0);
}
SetEvent(go);
}
In the first approach, workers are blocked on SleepConditionVariableSRW and woke up by WakeAllConditionVariable. In the second, they are blocked on WaitForSingleObject and woke up by SetEvent.
Which one is better in practice, only regarding overhead? (hint: context switch, lock contention, overhead of blocking threads)
I would choose the first but feel lack of justification.
Condition variables are used to wait until a particular condition predicate becomes true. This condition predicate is set by another thread, usually the one that signals the condition.
While mutex implement synchronization by controlling thread access to data, condition variables allow threads to synchronize based upon the actual value of data. Without condition variables, the programmer would need to have threads continually polling (possibly in a critical section), to check if the condition is met.
There are two types of actions that can be performed with condition variables: wait. signal.
This particular use case is ideal for an event: it's a one-shot process, where all waiting threads must be woken.
Condition variables are better suited for things like queues, where there is an associated predicate that may or not be true when the waiting thread wakes up (such as items on the queue --- they may have been consumed by another thread), or where it matters that the thread woken is one of those already waiting when the condition variable is notified, rather than one that comes along afterwards.
Plus, as Hans pointed out, Windows native condition variables only work on Vista or later, so you can't use them if compatibility with Windows XP is a concern.
Support for condition variables requires Vista or better. That's usually where the buck stops, supporting XP unfortunately tends to be still important. Your second snippet also does has the considerable advantage that it is trivial to understand. I don't have a clue what you're trying to do in the first one, it looks wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With