Condition variables are one of the aspects of c++11 I'm still struggling with a bit. From what I have gathered a condition variable is very similar to a semaphore.
But then again, a semaphore wouldn't need a lock to function. A condition variable does. And a lock in turn needs a mutex. So in order to use the fairly simple functionality of a semaphore we now need to not only manage a condition variable. But also a mutex and a lock.
So why does a condition variable need this? And what added functionality is provided by adding this requirement?
Condition variables are associated with a mutex because it is the only way it can avoid the race that it is designed to avoid.
If you didn't have a lock associated with the cv then your thread waiting on the cv might wake up then try to (and fail) to acquire the lock associated with the data and therefore have to yield again.
The pthread_cond_wait() function atomically unlocks mutex and performs the wait for the condition. In this case, atomically means with respect to the mutex and the condition variable and another threads access to those objects through the pthread condition variable interfaces.
A conditional variable in operating system programming is a special kind of variable that is used to determine if a certain condition has been met or not. It is used to communicate between threads when certain conditions become true. A conditional variable is like a queue.
Condition variables are generally used to signal a change of state. A mutex is usually needed to make that change, and the following signal, atomic.
A semaphore encapsulates some state (a flag or counter) along with the signalling mechanism. A condition variable is more primitive, only providing the signal.
In general once you've signaled something has changed (via a condition variable) you need some code to run to handle that change and that code has to safely read the changed data. If you didn't have a lock associated with the cv then your thread waiting on the cv might wake up then try to (and fail) to acquire the lock associated with the data and therefore have to yield again. With a CV/Lock combo the underlying system can wake your thread up only if the thread can acquire the relevant lock as a unit and so be more efficient.
Its unlikely a CV on its own is useful as it gives no data above the fact it was signaled. If you imagine uses of cv - such as a thread-safe linked list with producers and consumers, you have variables representing {list, cv, lock}
. In this case you take the lock, mutate the list, release the lock then signal the cv. On you consumer thread you'll very likely need to take the lock once signaled to act on the list, so having the lock acquired once you wake up from the CV being signaled is a good thing.
Look at something like events on windows (::CreateEvent) which are cv's without the implicit lock, a lot of the time they'll have a lock associated with them, but just not built into the actual usage.
Although this isn't the original reason condition variable in pthreads was created (they used the lock to protect the cv itself which is no longer needed in c++) the reason and usefulness of locks with cv's has migrated to whats in this answer.
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