Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does condition_variable::wait_for() deal with spurious wakeups?

Spurious wakup is allowed by various platforms. To counter that, we write below looping mechanism:

while(ContinueWaiting())
  cv.wait(lock);   // cv is a `std::conditional_variable` object

Same thing is understandable for conditional_variable::wait_until().
But look at below example:

const auto duration = Returns_10_seconds();
while(!Predicate())
  cv.wait_for(lock, duration);

Imagine that, spurious wakeup happened at 1 second. Timeout is not yet reached.
Will it wait for another 10 seconds? This would lead to infinite loop, which I am sure should not happen. From source code, internally wait_for() calls wait_until().

I want to understand, how does wait_for() deals with spurious wakeups?

like image 282
iammilind Avatar asked Aug 07 '15 06:08

iammilind


3 Answers

I want to understand, how does wait_for() deals with spurious wakeups?

It doesn't.

This function is typically used in a situation where if you wake up spuriously, you want to do some other work anyway. And if you don't wake up spuriously, you want to force a "spurious" wake up by the time duration has passed. This means it is not typically used in a loop as you show, for exactly the reasons you state. I.e. timeouts and spurious wake ups are treated identically.

Now you might be wondering, well, what does the predicate version do, as it implies a loop?

template <class Rep, class Period, class Predicate>
bool
wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time,
         Predicate pred);

This is specified to have the same effects as:

return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));

The wait_until variation does distinguish between spurious wake ups and timeouts. It does so with a loop like this:

while (!pred())
    if (wait_until(lock, abs_time) == cv_status::timeout)
        return pred();
return true;
like image 179
Howard Hinnant Avatar answered Oct 11 '22 21:10

Howard Hinnant


Here's what the standard has to say about spurious wakeups:

30.5 Condition variables [thread.condition]

Condition variables provide synchronization primitives used to block a thread until notified by some other thread that some condition is met or until a system time is reached.

...

10 Note: It is the user’s responsibility to ensure that waiting threads do not erroneously assume that the thread has finished if they experience spurious wakeups.

From the wording it seems pretty clear that the responsibility for dealing with spurious wakeups is on the user.

like image 3
blockchaindev Avatar answered Oct 11 '22 21:10

blockchaindev


    const auto duration = Returns_10_seconds();
    while(cv.wait_for(lock, duration) == std::cv_status::timeout);

This is definitely a wrong thing to do and thus does not make sense discussing how to fix it for the case of spurious wakeups, as it is broken even for the case of ordinary wakeups, because the wait condition is not re-examined after returning from the wait.

const auto duration = Returns_10_seconds();
while(!Predicate())
  cv.wait_for(lock, duration);

Even after the edit, the answer stays the same: you can't really handle "spurious wakeups", because you can't really tell the reason for the wakeup - it may well be a completely legit wakeup due to a call to condition_variable::notifyXXX before the timeout has expired.

First, note that you can't really distinguish between a wakeup caused by a call to condition_variable::notifyXXX and wakeup caused by, for example, a POSIX signal[1]. Second, even if POSIX signals are not of concern, the waiting thread still must reexamine the condition as it is possible for the condition to change between the time the condition variable is signaled and the waiting thread returns from the condition wait.

What you really have to do is treat in a special manner not waking up before the timeout, but waking up due to timeout. And that entirely depends on the reasons to have a timeout in the first place, i.e. on the specifics of application/problem domain.

[1] if wait on a condition variable is interrupted by a signal, after executing the signal handler the thread is allowed either to resume wait or return

like image 1
chill Avatar answered Oct 11 '22 19:10

chill