
Alexander Bernauer wrote:
I wasn't aware of the fact that it is not required to have the mutex acquired when calling notify_*.
I believe it is preferred to not have the lock held because you can then have fewer context switches: if you notify with the lock held the waiting thread may be scheduled but it will immediately block trying to re-acquire the mutex, and the first thread will be scheduled again to release it. I haven't measured the effect this though. Is anyone aware of a correctness reason for not notifying with the lock held?
AFAICS, in order to trigger the notification one has to acquire the lock anyway, because the waiting thread loops around some value of a state, which one has to alter concurrently.
Yes, i.e. lock mutex change state unlock mutex notify condition
So, I can see no additional penalty when encapsulating spurious wakeups.
You have the penalty of actually doing the spuriousness check and storing the extra state, as you described in your first post.
I am aware of the wait functions, which accept a predicate and do the loop for you. My point is, that expressing the loop condition is not always trivial. Therefore in those cases - at least up to my experience - normaly new flags or counters are introduced, which signal "Yes, it was really intended that you woke up". This is cumbersome.
Can you give an example? If your condition is very slow to evaluate and spurious wakeups are common then you may save time by eliminating the possibility of spuriousness before evaluating the condition. But my experience is that spurious wakeups are rare in practice. (The exception might be if your application makes a lot of use of signals, e.g. async IO or timers.)
On the other hand those flags/counters are a safe way to solve the spurious wakeup problem in general. So why not having the library doing the job?
Well, it makes things slower for users whose conditions are simple or who have infrequent spurious wakeups.
Not to mention the fact that spurious wakeups are a very hard to detect bug in case one forgets to loop
Every instance of waiting on a condition should always be in a loop, or use the predicate version of wait.
or - even worse - there is a bug in the loop condition.
Regards, Phil.