std::condition_variable::wait with predicate
Asked Answered
D

2

10

In the documentation for std::condition_variable, there is an overload of wait() taking as argument a predicate function. The function will wait until the first wake_up at which the predicate function is true.

In the documentation

It is stated that this is equivalent to:

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

But also:

This overload may be used to ignore spurious awakenings while waiting for a specific condition to become true. Note that before enter to this method lock must be acquired, after wait(lock) exits it is also reacquired, i.e. lock can be used as a guard to pred() access.

I'm not sure to understand, are these strictrly equivalent (in which case I prefer the plain while loop which is easier to read than the overload with a lambda in my case), or is the overload (possibly implementation depending) more efficient?

Could an implementation evaluate the predicate in the notifying thread before awakening the waiting thread, in order to avoid awakening when the test condition is false? c++ thread guru needed here...

Thanks

Dissipated answered 13/11, 2015 at 12:16 Comment(0)
H
5

Implementations can try to make it better than the loop from performance standpoint, but I doubt it is possible. It is very straitghtforward, and you can check your implementation to see how it is done. This is what gcc 4.9.2 does here:

template<typename _Predicate>
  void
  wait(unique_lock<mutex>& __lock, _Predicate __p)
  {
      while (!__p())
        wait(__lock);
  }

As you can see, it is exactly the same, and I doubt something else can be done here. As for readability, it is more readable than loop. However, you probably misunderstand the reason for this. This loop is simply supposed to check that the real variable guaraded by condition did indeed change to the value you expect it to be - as it might have not. The usual code snipped looks like this:

cond_var.wait(lock, []() { return bool_var == true; })
Halfprice answered 13/11, 2015 at 14:39 Comment(4)
This was my understanding of the purpose of this function. But from the documentation, I understood that the overload could avoid awakening the thread in cases the variable did not change. This would mean that the Predicate object is evaluated in another thread (such as the notifying thread) before effectively awaking the waiting thread. Thus being more efficientDissipated
@Dissipated No, it can not. It is based on pthread conditional variables, and those do have spurious wake-ups.Halfprice
The standard is not based on pthreads, nor all implementations. And windows threads have more possibilities than pthreads in this regard if I'm right (as I'm using mingw-gcc I have the choice)Dissipated
@galinette, standard never says so, of course. But it is obvious if you compare two APIs. And in particular, mingw gcc uses Posix-compatible wrapper provided by mingw (mingwthrd or something to that effect), so as far as gcc sees it, it is Posix.Halfprice
S
0

As far as my understanding goes these two (a while loop and wait + predicate) are functionally equivalent. If you'd use while loop, lock should be acquired before entering and evaluating the loop condition first time. Every other time you would also hold the lock as predicate() would execute after wait() has completed.

The overload internally does the same thing: you have to acquire the lock before calling wait, and after wait is completed the predicate() is internally invoked to check if we should continue waiting (just like while loop would do).

Perhaps you're right, for simple predicates that simply return a boolean value using while loop is clearer. But what if predicate becomes more complex? Define a dedicated function for it and use it in a while loop condition, or use in place lambda? What if number of predicates grow, will you define function for each of these? In my opinion, using lambdas in this case makes the code clearer as entire things is kept together in a single logical unit.

Stairs answered 13/11, 2015 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.