8

If std::condition_variable can be signaled due to the spurious wakeups (and we can't be sure that the condition we need is really satisfied), why do C++ Standard Library provide the overloads of wait() method without a predicate? What are the scenarios when such behaviour can be used?

undermind
  • 1,779
  • 13
  • 33
  • 1
    I can only guess that because traditionally posix and windows API provided condition variable without a predicate the comitee wanted to preserve the original use/API of them but with a standard , portable form. other than that, I see no reason using cv's without predicate – David Haim Jan 26 '16 at 11:58
  • Historically, it was accepted that system calls, eg. those for inter-thread comms, worked correctly every time they were called. – Martin James Jan 26 '16 at 12:05
  • 1
    @MartinJames The implementation can't prevent spurious wakeups. It's not a matter of the system call working correctly, it's the inherent race between a thread that is deciding whether to block and a thread that is unblocked but not yet running. (For example, two messages go on a queue. We wake two threads. If the first thread processes both messages, the second thread will see a spurious wakeup.) – David Schwartz Jan 26 '16 at 12:07

3 Answers3

7

Assume a complex condition: A || B. When any part of the condition is true, appropriate action, actionA or actionB, should be perfomed.

Using predicate version, the code could be following:

cond.wait(lock, []{return (A || B);});
if(A) {
    actionA();
}
else {
    actionB();
}

But the code may be faster if use non-predicate wait:

while(true)
{
    if(A) {
         actionA();
         break;
    }
    else if(B) {
         actionB();
         break;
    }
    cond.wait(lock);
}

Note, that unlike to the first variant, now every condition part is evaluated once.

There are more complex cases, when a condition cannot be written in a single expression.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • If you imagine complex code where different things inside the predicate test result in different flows of control, you could wind up with either an overly-complex predicate or an ugly structure just to get information out of the predicate and restore the right point in the flow of control. – David Schwartz Jan 26 '16 at 12:03
  • @DavidSchwartz: It depends. The simplest example of two-part condition with different reactions is reading a queue which may be ended(EOF). As for `over-complex` and `ugly structure` - multithreading by itself is a complex thing. Sometimes it is desireable to sacrifice program readability for simplify multithreaded aspects. – Tsyvarev Jan 26 '16 at 12:16
4

why do C++ Standard Library provide the overloads of wait() method without a predicate

The predicate version of wait is equivalent to:

while (!pred()) {
    wait(lock);
}

If you need more complex code to be executed before and/or after waiting you may like to use wait without the predicate.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
3

I guess there are cases where spurious wakeups are not the end of the world.

E.g., consider a producer-consumer batch processing system, where some thread should wake up when there are, say, at least 100 messages in a queue, and process them.

Given spurious wakeups, it might reap fewer than 100 messages, occasionally. The difference might not warrant the overhead and extra complexity of the condition function.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • 1
    This is an example of a case where you'd either have to put the actual code to reap the messages in the predicate to avoid the extra overhead or use a dummy predicate that tests nothing. Either of those solutions would be ugly. – David Schwartz Jan 26 '16 at 12:05