Re: JavaMemoryModel: Most (all?) JVM's incorrectly handle volatile reads-after-writes

From: Doug Lea (dl@altair.cs.oswego.edu)
Date: Tue Nov 23 1999 - 08:55:14 EST


First, for those curious about it, I determined that there IS at least
one potential trace in FJTasks that will fail under VMs that do not
ensure proper read-after-write of volatiles. The case is extremely
rare, and might never arise in practice. But this is of course not a
good enough assurance. Considering Bill's evidence that no VM he
tested properly handles read-after-write, I need to release a version
that uses locking. (Unfortunately, the lock-based versions I've tried
so far are up to 20% slower in some tests, although only a couple of
percent slower in the most realistic ones.)

In this and other frameworks, classes and utilities I write, I could
do a better job, without having to tread in dark corners of the
language, if I just had direct access to memory barriers. Rather than
trying to twist the overall memory model to somehow get the right
effects in the right contexts, how about just doing the obvious, and
creating:

class java.lang.MemoryBarrier {
  public static native void loadStoreBarrier();
  public static native void loadLoadBarrier();
  public static native void storeLoadBarrier();
  public static native void storeStoreBarrier();
}

(Or, pick better names if you can think of some.)

This is a class that most people would never want to even know
about. But people like me who are trying to built efficient classes
that non-concurrency-experts in turn use, can exploit these to create
occasionally much faster lock-free code.

Note that on most uniprocessors, the native implementations of
all these methods could just be no-ops. Various multiprocessors
can optimize away the ones they doen't really need.

It looks hard to explain the effects of these methods in terms of the
overall memory model, especially Bill's LC-based proposal, but it
ought to be possible.

A bit more rationale for wanting these:

Tying locks to memory effects is normally a good idea. But it is much
less good when you not only do not need exclusion, but you do not want
it because using a lock will lead to lock contention across
threads. This uselessly slows down programs where many threads all
contend for a lock that they don't even need. Contention is a much
more serious problem than lock overhead in some programs/algorithms.

The main place where this arises is concurrently readable data
structures -- data structures that are always kept in a consistent
enough state to be read without locking (updates require either locks
or CASes), but do require barriers to ensure visibility. These,
normally optimistically-based data structures and algorithms are
deservedly becoming popular in concurrent systems programming -- they
almost always perform better than classic lock-based versions.
Supporting a class such as MemoryBarrier, as well as classes natively
implementing CAS (as David Bacon and I mentioned in previous posts),
would allow people to implement these without the need for sleazy
tricks and workarounds.

Also, if this were adopted, I would hardly ever use volatiles, which
means that I would stop caring if they were atrociously slow, and
designed for people who want to stay in SC mode.

-Doug



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:23 EDT