Both thread safety and liveness are concerns when using condition variables. The thread-safety property requires that all objects maintain consistent states in a multithreaded environment [Lea 2000]. The liveness property requires that every operation or function invocation execute to completion without interruption; for example, there is no deadlock.
Condition variables must be used inside a while
loop (see CON36-C. Wrap functions that can spuriously wake up in a loop for more information). To guarantee liveness, programs must test the while
loop condition before invoking the cnd_wait()
function. This early test checks whether another thread has already satisfied the condition predicate and sent a notification. Invoking the cnd_wait()
function after the notification has been sent results in indefinite blocking.
To guarantee thread safety, programs must test the while
loop condition after returning from the cnd_wait()
function. When a given thread waits (cnd_waitinvokes the cnd_wait()
function, it will attempt to block until its condition variable is signaled by a call to cnd_broadcast()
or to cnd_timedwaitsignal()
.
The cnd_signal()
on a function unblocks one of the threads that are blocked on the specified condition variable at the time of the call. If multiple threads are waiting on the same condition variable, it can be awakened as a result of a signal operation (cnd_signal()
). However, if multiple threads are waiting on the same condition variable, any of those threads can be selected by the scheduler to be awakened (assuming that all threads have the same priority level).
The programmer is forced to create a predicate-testing loop around the wait condition to guarantee that each thread executes only if its predicate test is true (recommendation in IEEE Std 1003.1 since the 2001 release [IEEE Std 1003.1-2004]). As a consequence, if a given thread finds the predicate test to be false, it waits again, eventually resulting in a deadlock situation.
the scheduler can select any of those threads to be awakened (assuming that all threads have the same priority level). The cnd_broadcast()
function unblocks all of the threads that are blocked on the specified condition variable at the time of the call. The order in which threads execute following a call to cnd_broadcast()
is unspecified. Consequently, an unrelated thread could start executing, discover that its condition predicate is satisfied, and resume execution even though it was supposed to remain dormant. For these reasons, threads must check the condition predicate after the cnd_wait()
function returns. A while
loop is the best choice for checking the condition predicate both before and after invoking cnd_wait()
.
The use of cnd_signal()
is safe if each thread uses a unique condition variable. If multiple threads share a condition variable, the The use of cnd_signal()
is safe only if the following conditions are met:
- All threads must perform the same set of operations after waking up, which means that any thread can be selected to wake up and resume for a single invocation of
cnd_signal()
. - Only one thread is required to wake upon receiving the signal.
...
- wake upon receiving the signal.
The use of cnd_broadcast()
avoids these problems because it wakes up all the threads associated with the condition variable, and because all the threads must reevaluate the predicate condition, one thread will find its test to be true, avoiding deadlock function can be used to unblock all of the threads that are blocked on the specified condition variable if the use of cnd_signal()
is unsafe.
Noncompliant Code Example (cnd_signal()
)
...