The reason of necessity of using while loop is there are only two functions in the std::condition_variable
for awakening waiting threads:
notify_one()
which awakes one of the threads currently waiting for this condition without possibility to point which one to awake exactly.
notify_all()
which awakes all threads currently waiting for this condition.
And because std::condition_variable has only two functions to awake waiting threads you will either awake one random thread by using notify_one()
or awake all waiting threads by using notify_all()
.
Obviously that is not satisfying and we need somehow to point which one thread is to awake. And in that situation this semantic can help:
while (!ready) cv.wait(lck);
rest part of the code
here, ready
- the result of predicate which will return true only when particular condition you need takes place.
Quotation:
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.
Condition wait semantics
A condition predicate must be protected by a mutex. When waiting for a
condition, the wait subroutine (either the pthread_cond_wait or
pthread_cond_timedwait subroutine) atomically unlocks the mutex and
blocks the thread. When the condition is signaled, the mutex is
relocked and the wait subroutine returns. It is important to note that
when the subroutine returns without error, the predicate may still be
false.
The reason is that more than one thread may be awoken: either a thread
called the pthread_cond_broadcast subroutine, or an unavoidable race
between two processors simultaneously woke two threads. The first
thread locking the mutex will block all other awoken threads in the
wait subroutine until the mutex is unlocked by the program. Thus, the
predicate may have changed when the second thread gets the mutex and
returns from the wait subroutine.
In general, whenever a condition wait returns, the thread should
reevaluate the predicate to determine whether it can safely proceed,
should wait again, or should declare a timeout. A return from the wait
subroutine does not imply that the predicate is either true or false.
It is recommended that a condition wait be enclosed in a "while loop"
that checks the predicate.
Additionaly:
According to difficulty with creating awakening conditions, which might be unpredictable in multithread systems, threads may wake up whenever for whatever reason. That is called Spurious wakeup. Solution: Use loop to always check a condition variable.