Why do you need a while loop while waiting for a condition variable
Asked Answered
K

4

24

Say you have this code

pthread_mutex_lock(&cam->video_lock);
while(cam->status == WAIT_DISPLAY) // <-- Why is this a 'while' and not an 'if'?
    pthread_cond_wait(&cam->video_cond, &cam->video_lock);
pthread_mutex_unlock(&cam->video_lock);

My question is, why do you need a while loop here. Wouldn't pthread_cond_wait just wait until the signalling thread signals cam_video_cond? OK, I know you might have a case where cam->status is not equal to WAIT_DISPAY when pthread_cond_wait is called, but in that case you could just check it through an if condition rather than using while.

Am I missing something here? My understanding of pthread_cond_wait is that it just waits for infinite if cam_video_cond is not signalled. Moreover, it unlocks the cam_video_lock mutex when called, but when the condition is signalled, before returning, it relocks cam_video_lock. Am I right?

Kristiekristien answered 14/10, 2011 at 10:3 Comment(2)
Same question here, unix.com/programming/149791-condition-variables.htmlKristiekristien
Spurious wakeupMistral
M
26

It is recommended that all threads check the condition after returning from pthread_cond_wait because there are several reasons the condition might not be true. One of these reasons is a spurious wakeup; that is, a thread might get woken up even though no thread signalled the condition.

Source : Spurious wakeup

Mistral answered 14/10, 2011 at 10:23 Comment(0)
M
21

Spurious wakeups are one reason, but legitimate but extraneous wakeups are another.

Consider:

  1. You put a job on a queue.

  2. You signal the condition variable, waking thread A.

  3. You put a job on a queue.

  4. You signal the condition variable, waking thread B.

  5. Thread A gets scheduled, does the first job.

  6. Thread A finds the queue non-empty and does the second job.

  7. Thread B gets scheduled, having been woken, but finds the queue still empty.

Miosis answered 26/10, 2011 at 22:43 Comment(2)
But in your example, at 2, when thread A wakes up, it automatically locks the resource , so at 4, since the mutex is still locked , does the OS actually wakes up thread B?Healy
@Healy While thread A is doing the job at step 5, it does not hold any mutex. The thread that put the job on the queue has to have released the mutex by that point as well. Thus only thread B could hold the mutex, so the OS must wake thread B.Miosis
F
4

For performance reasons, the POSIX API allows the OS to wake up your thread even if the condition has not been fulfilled (that's called a spurious wakeup).

Flattop answered 14/10, 2011 at 10:22 Comment(0)
A
2

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.

Azucenaazure answered 13/8, 2021 at 17:36 Comment(1)
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. should be highlightedInfantry

© 2022 - 2024 — McMap. All rights reserved.