When can std::condition_variable be used without a predicate?
Asked Answered
S

3

9

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?

Salaried answered 26/1, 2016 at 11:30 Comment(3)
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 predicateLugo
Historically, it was accepted that system calls, eg. those for inter-thread comms, worked correctly every time they were called.Demetrius
@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.)Seda
D
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.

Dripdry answered 26/1, 2016 at 11:57 Comment(2)
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.Seda
@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.Dripdry
V
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.

Vareck answered 26/1, 2016 at 12:11 Comment(0)
P
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.

Pterous answered 26/1, 2016 at 12:2 Comment(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.Seda

© 2022 - 2024 — McMap. All rights reserved.