Stallings' Operating System book says about condition variable in Solaris,
A condition variable is used to wait until a particular condition is true. Condition variables must be used in conjunction with a mutex lock. This implements a monitor of the type illustrated in Figure
6.14 . The primitives are as follows:cv_wait() Blocks until the condition is signaled cv_signal() Wakes up one of the threads blocked in cv_wait() cv_broadcast() Wakes up all of the threads blocked in cv_wait()
cv_wait() releases the associated mutex before blocking and reacquires it before returning. Because reacquisition of the mutex may be blocked by other threads waiting for the mutex, the condition that caused the wait must be retested. Thus, typical usage is as follows:
mutex_enter(&m) * * while (some_condition) { cv_wait(&cv, &m); } * * mutex_exit(&m);
This allows the condition to be a complex expression, because it is protected by the mutex.
Operating Systems: Three Easy Pieces says about condition variable:
We will often refer to these as wait() and signal() for simplicity. One thing you might notice about the wait() call is that it also takes a mutex as a parameter; it assumes that this mutex is locked when wait() is called. The responsibility of wait() is to release the lock and put the calling thread to sleep (atomically); when the thread wakes up (after some other thread has signaled it), it must re-acquire the lock before returning to the caller. This complexity stems from the desire to prevent certain race conditions from occurring when a thread is trying to put itself to sleep.
In Operating System Concepts, a signal-and-wait condition variable is implemented as:
We can now describe how condition variables are implemented as well. For each condition x, we introduce a semaphore x sem and an integer variable x count, both initialized to 0. The operation x.wait() can now be implemented as
x count++; if (next count > 0) signal(next); else signal(mutex); wait(x sem); x count--;
The operation x.signal() can be implemented as
if (x count > 0) { next count++; signal(x sem); wait(next); next count--; }
This implementation is applicable to the definitions of monitors given by both Hoare and Brinch-Hansen.
Questions:
Why is it that "cv_wait() releases the associated mutex before blocking and reacquires it before returning" in the first book?
What are the race conditions in "This complexity stems from the desire to prevent certain race conditions from occurring when a thread is trying to put itself to sleep" in the second book?
Why does the implementation of wait() in the third book not performing "releases the associated mutex before blocking and reacquires it before returning" in the first book? Is this a mistake in the third book, or is release and require not needed for a Hoare's monitor (signal-and-wait), but only needed for a Mesa's monitor (signal and continue)?
Why is it that "Because reacquisition of the mutex may be blocked by other threads waiting for the mutex, the condition that caused the wait must be retested" in the first book?
Thanks.