
Roland Schwarz wrote:
He can, but this kind of defeats the purpose of using the predicate version in the first place. It is supposed to guard against spurious wakeups, so it makes sense to also make it guard against stolen wakeups.
I agree we could change semantics this way, but I still cannot understand why you think the wakeup is stolen? You have access to it by evaluating pred.
"Spurious wakeup" means that a thread is awakened without reason. "Stolen wakeup" means that a thread consumes a wakeup intended for another thread. When a timeout expires _and_ the thread consumes a signal, this signal in a perfect world (where only one of the two events occur at a given moment) would have been delivered to another waiting thread. Hence, "stolen wakeup". You have two threads waiting on a condition, two events happen at the same time, a signal and the first thread timing out. Delivering both to the first thread is error prone. Most client code that uses timed waits does not handle this situation.
Say we have a thread that makes a call to start an external device e.g. a motor at time t0. Say we have a second thread that is monitoring the RPM of the motor and signalling a condition if it has reached its nominal value. The first thread meanwhile is waiting on this condition with a timed wait say t0+t_emergency. Now lets assume motor specs. dictate it is essential to immediately stop the device if it hasn't reached nominal RPM within t_emergency. Doesn't your proposed change just hide this fact, and the motor thus might break?
Why would it hide it?
But again, I think I possibly cannot see your point clear enough yet. Can we agree that the current version is not wrong?
It does what the specification says it does, so it is not "wrong" in this sense. I'm arguing that the specification needs to be changed.
You are just suggesting a possibly better less error prone semantics? If so please try to elaborate it a little more.
The idea of supplying a predicate version is to guard against common user mistakes. For the ordinary wait, the predicate version ignores spurious wakeups. It is very easy to assume that spurious wakeups don't occur and write incorrect code based on this assumption. So we supply a version where they don't. For timed_wait, there is an additional source of subtle bugs, the fact that a timeout and a signal can both occur and be "delivered" to the same waiting thread. You can't express this in a simple true/false return value, so you have to map the three possible outcomes into two (the fourth outcome is a spurious wakeup and is never returned). I argue that the predicate version should attempt to guard against this additional incorrect user assumption (that only one of a signal occuring or a timeout elapsing happens and not both), too. To get back to you example, if (!timed_wait(lk, xt, pred) && !pred()) { // handle timeout } have you ever seen such code? I haven't. if (!timed_wait(lk, xt, pred) ) { // handle timeout } is the norm (and pred is usually something lambda-ish). The low-level non-predicate version is available for those that are interested in the "raw" return value from the wait.