[concurrency-interest] spurious wakeups semantics

Brian Goetz brian at quiotix.com
Wed Nov 2 13:27:57 EST 2005


Your argument is mostly an "aesthetic" one, and you are contorting the 
world to fit your sense of aesthetic.  Spurious wakeups were not 
invented because we like ugliness; they were a real-world engineering 
compromise.  I presume you posted here because you wanted to understand 
the issue.  But using words like "broken" (incorrectly, I might add) 
does little to enlist the aid of those here.

> Matthias and Tim both raise the defence for while-not-condition-wait-loops
> with the classical argument that something might have unset the waited-for
> condition between the notifyer setting it up and the waiter reacquiring
> the monitor.  Of course that may happen ... but only if the logic in the
> programmed system is sloppy (I used the term "lazy" last time).

BZZZT.

- This can happen whenever a single wait set is used for multiple 
conditions.  Until Java 5, this was the _only_ way to get multiple 
conditions on a single condition queue, and you still can't with 
intrinsic condition queues.  So what should we do?  Outlaw bounded 
buffers, and other concurrent objects which require more than one 
condition?

- This can happen whenever notifyAll is used to wake up more than one 
thread, even if all threads are waiting for the same condition.  There 
are good engineering reasons why you might prefer notifyAll to single 
notify.

These cases don't describe "sloppiness", they describe sensible 
practices for common real-world problems.

>>A trivial implementation of a concept does not render the concept
>>nonsensical.  The implementation is just not useful then.
> 
> But our programs must survive being executed on such a useless, but legal,
> implementation.  I suspect most would not?  The fact that a trivial
> implementation of a concept might exist means that our use of the concept
> must cope with that implementation ... and if it can't, that renders
> the concept (or at least our use of it) useless.

The standard idioms cope with that quite well.   Such an implementation 
would just perform poorly.  Which is one reason why it would be a poor, 
albeit valid, implementation.

   synchronized (lock) {
     while (!conditionPredicate())
        lock.wait();
   }

will work fine if wait() is simply an unlock^n-lock^n sequence.  And the 
JLS requires it to release the lock as part of a wait, so the 
unlock^n-lock^n cannot be optimized away.  See JLS/3e 17.8.1.  (You 
might consider looking at the spec before making claims like "X would be 
a valid implementation, but that would break real programs" when the 
spec very clearly outlaws X.)

> It's surely much better for the JVM to protect the Java system from broken
> OS threading mechanisms.  

You have done nothing to support your claim of brokenness.  As far as I 
can tell, all you've said is that you personally find it ugly.  You may 
be right, but that doesn't mean its broken.

> Allowing the spurious wakeups through has an
> effect of performance as well -- pulling the woken thread off the wait-set
> and into the acquire-the-monitor-set, scheduling that woken thread,
> executing its code to test (folornly) its while-condition, and finally
> putting that woken thread back in the wait-set and scheduling another
> thread.  That doesn't look too attractive.

OS'es which permit spurious wakeups may do so because by doing so 
because they can improve overall performance.  Again, I refer you to the 
fair/nonfair issue with locks.  Sure, fairness is prettier, but 
starvation-free nonfair locks can be implemented a lot more efficiently. 
    To make a performance argument, you'd have to analyze the 
performance costs of rewriting the OS as you suggest.

> I would hope that - alongside converting while-wait-loop to if-wait -
> they would look very carefully at the logic of their monitor methods
> to ensure that the condition can't be unset between notification and
> re-acquisition.  

I share your hopes, but I've met enough real programmers to know that 
this is in the same category as hoping to wake up taller tomorrow.

> Clean mathematical abstractions are *necessary* (though not sufficient)
> for clean - and, hence, fast, simple and efficient - systems.  Hoare's
> mathematical abstractions have proved pretty successful in guiding some
> really spectacular engineering developments that deal with real messy
> life.

Except that a monitor-based design for a system of even moderate 
complexity will almost certainly deadlock.  This is (one reason) why the 
monitor-like approach that Java uses was taken over "real" monitors.

> It's the absence of clean mathematical abstractions that leads to real
> engineering costs (that you mention).  I just don't believe that never
> delivering a spurious wakeup should impose such a cost (assuming we're
> not trying to guard against hardware corruption).

This one I buy.  But the abstractions need to be consistent with the 
reality of hardware and OSs of the day.



More information about the Concurrency-interest mailing list