[jmm-dev] Does a volatile load have to see the exact volatile store to synchronize?

Hans Boehm boehm at acm.org
Sat Apr 28 01:07:26 UTC 2018


[ This was previously posted to a smaller audience. Reposting here as the
next step. ]

This seems to be a new Java memory model problem uncovered in response to
the revision of "release sequences" in C++. wg21.link/P0982 has details.
But if you don't care about the C++ memory model, you can ignore all that
and just read the following.

Clearly this isn't the only or most serious open Java memory model problem.
But I think it's actually one that has a fairly simple point solution. And
it may be worth fixing without a comprehensive solution.

Problematic litmus test:

Writing =rlx for ordinary Java memory accesses and =sc for volatile ones,
consider

Thread 1:
x =plain 1;
v =vol 1;

Thread 2:
v =vol 2;

Thread 3:
r1 =vol v;
r2 =plain x;

Java disallows the final state, after joining all threads, of r1 = v = 2
and r2 = 0. Since in the end v = 2, Thread 2s assignment to v must have
followed Thread 1's  in the synchronization order. And in Java a volatile
store synchronizes with all later (in synchronization order) volatile loads
(Property A). This Thread 1 must synchronize with Thread 3, and r2 must be
1.

This diverges from the analogous C++ semantics. (The release sequence
problem there is a bit different.)

The consensus of the experts in the other discussion is that this outcome
is in fact allowed on Power, with both of the standard compilation models.
Thus the spec and the implementations can't both be right in this regard.

IIRC, the JMM discussion that led to this, like the one that led to the
vaguely analogous C++ problem, was more of a "why not" argument then
anything solid. Which in retrospect was probably unwise in both cases.
That, combined with the fact that this is a C++ vs Java divergence, and the
expense of actually conforming to the current spec on Power, suggests we
may want to call this a spec problem.

The concrete proposal would be to change the bullet (in 17.4.4)

* A write to a volatile variable v (§8.3.1.4) synchronizes-with all
subsequent reads of v by any thread (where "subsequent" is defined
according to the synchronization order).

to (for now)

* A write w to a volatile variable v (§8.3.1.4) synchronizes-with any read
of v that observes the value written by w.

The reason I said "for now" is that I think we will eventually need
C++-style "release sequences" in order to prevent intervening RMW
operations from breaking the synchronizes with relationship here. Without
that some fairly basic idioms, like reference counting, would look
different in Java and C++, with Java being needlessly slower. But RMW
operations aren't yet a thing in the JLS, so we can leave that in the
bucket of other things that will eventually need fixing.

The argument for doing this now rather than later is that the spec clearly
promises something that fails to hold for major implementations. And
somewhat uniquely, in this case, we do know how to fix it. There is no
reason to provide misleading information here.

Opinions?

Hans


More information about the jmm-dev mailing list