Re: spurious wakeup
From: Marcin 'Qrczak' Kowalczyk (qrczak_at_knm.org.pl)
Date: Sun, 28 Nov 2004 01:39:22 +0100
Sorry, I don't read comp.lang.c++, and my response is more about threading
than about C++, so I'm setting Followup-To back to comp.programming.threads.
Markus.Elfring@web.de (Markus Elfring) writes:
>> That's a lot of lines compared to while (!predicate) wait(condition);
> If you want to provide protection against spurious wakeups by a
> library function or method, you need to pass the predicate and the
> surrounding and corresponding code as (template) parameters.
The while loop protects against spurious wakeups too. It's not a
method, but so what? It can be wrapped in a macro if you insist on
a simpler syntax.
> Would you like to use a similar service quality like it is available
> for the algorithms "std::for_each()" and "std::find_if()"?
In these cases:
- it's not the only solution available: you can advance iterators
- the corresponding loop is a bit more complex than this while loop,
so it's more often a win than here.
You can provide a function which takes the predicate as an object,
but I would not like to be forced to use it as the only option. It's
equivalent to the while loop anyway, so it doesn't provide anything
new. And the while loop is usually easier to write because C++ lacks
In general I avoid C and C++ all, except for implementing a runtime
of a higher level language.
>> If the condition variable is wrapped together with the predicate, I
>> expect waiting to be equivalent to the above while loop, because this
>> is the classic pattern of waiting for a condition. In this case it
>> doesn't matter whether the "raw" condition wait has spurious wakeups
>> (the predicate should not have side effects and should not take too
>> long to compute). When the predicate is satisfied, the waiting
>> function returns.
> It does matter if the documentation leaves out that spurious wakeups
> can happen.
Then it's the documentation that should be fixed.
My model of usage of conditions assumes that:
- Each condition is associated with a predicate, which is consistently
used for waiting for the condition (but see below).
Technical note: in languages with function closures the predicate
is better physically attached to the condition; in languages without
closures an explicit while loop will be easier to use. The semantics
is the same in either case, as long as you stick to the conventions.
- The predicate doesn't have side effects and takes a short amount of
time, thus it doesn't matter how often it's called.
- Soon after each state change which *may* cause the predicate to
change from false to true and which is followed by releasing the
mutex, the thread calls Notify / pthread_cond_broadcast / notifyAll
/ PulseAll (whatever it's called in the given language or threading
You may safely notify in more cases than needed (degrading
performance), but you must not notify less.
Even though the set of places where notification should be inserted
is roughly determined by the semantics of the code (modulo the fact
that it can be larger than needed if it's more convenient), the
programmer must do this himself. It's because it is impractical
for the compiler to detect all such cases automatically. An easily
automatizable safe approximation (e.g. notifying in all cases when
the mutex is being released) is too wasteful.
- The call to Notify can be optimized to Notify1 / pthread_cond_signal
/ notify / Pulse, in case we know that any waiting thread will cause
the predicate to become false again (or will notify another thread
itself), and thus at most one thread will benefit from being woken up.
This optimization is optional. You can stick to always notifying all
threads (degrading performance), but you must not apply it when more
than one thread should be woken up.
Again it is done manually because automatic detection by the
compiler of cases when it is safe to apply would be too hard.
Note that it's the broadcast version which is the conceptual
default. I think that languages which give the wake-up-one-thread-only
version a simpler name had made a worse choice of names.
Under these assumptions it doesn't matter whether the low-level
condition wait has spurious wakeups. There are no cases when the
predicate has become true, yet no waiting thread should be woken up
now, and the code would try to archieve that by omitting a call to
notify. This would not work (a thread could be woken up nevertheless
because of a spurious wakeup), but this never happens under these
assumptions. The code must be careful to notify in *all* cases when
the predicate might have changed to true. And if it did not change,
a spurious wakeup has no visible effect.
I believe these assumptions cover all practical uses of conditions,
i.e. using low-level condition primitives in ways not adhering to
the assumptions is never necessary. A minor speed-up caused by e.g.
evaluating the predicate after low-level waiting at least once
(if we know it was false before the loop) is really minor.
Well, in my language I allowed one extension of these assumptions
(after someone's advice in c.p.treads, and without a concrete
practical use case in mind): the predicate can be slightly different
in various invocations of Wait on the same condition, i.e. you can
supply a different predicate during waiting, which replaces the
predicate stored in the condition. All variations must be covered
by notification of course. This usage is probably very rare.
-- __("< Marcin Kowalczyk \__/ firstname.lastname@example.org ^^ http://qrnik.knm.org.pl/~qrczak/