[concurrency-interest] About putOrdered and its meaning

Aleksey Shipilev aleksey.shipilev at oracle.com
Wed May 4 10:08:11 EDT 2016


On 05/04/2016 11:42 AM, Romain Colle wrote:
> I've been recently trying to wrap my head around the meaning of
> Unsafe.putOrderedXXX() and how it differs from a volatile store.

> If I understand correctly, putOrdered shares some guarantees with a
> volatile store, notably that all the preceding stores from the same
> thread will be made visible to other threads before the ordered store.
> The main difference (from a hardware point of view) seems to be that the
> ordered store (and preceding ones) are not immediately flushed to main
> memory and may only be visible locally for a while.
> Is that correct?

putOrdered is a release in disguise, most of the C++11 std::atomic(...,
mem_order_release) reasoning applies here. "Flushed to main memory" is a
very unhelpful model on current hardware.

There is no way to specify this in the realm of current Java Memory
Model, so explanation should really deviate from it. My own mental model
is this: acquire/release are the relaxations from the usual volatile
rules -- while producing happens-before-s, they drop from total
synchronization order, thus breaking sequential consistency.

In practice, this means at least the absence of total order of
ordered/volatile reads/writes; or, as Javadoc says, the release writes
might not be visible to other threads [in the order you'd expect from
volatile reads/writes -- Edit: me] immediately, until the next
synchronization action happens.

See e.g.:
  http://cs.oswego.edu/pipermail/concurrency-interest/2016-March/015037.html


> In this case, do we need anything more to guarantee safe Object
> publication and happens-before relationships? More specifically:
> 
> 1) I want to safely publish an Object, i.e. make sure it has been fully
> built and initialized before making it visible to other threads.
> In the absence of final fields (which should be enough by themselves),
> can I simply use a putOrdered instead of a volatile write?

I think you are conflating safe construction and safe publication there.

Safe publication still works:

                       int x; volatile int y;
-----------------------------------------------------------------------
    put(x, 1);                   |  r1 = get{Acquire|Volatile}(y);
    put{Release|Volatile}(y, 2); |  r2 = get(x);

(r1, r2) = (2, 0) is forbidden.

But anything trickier that requires sequential consistency fails. IRIW
fails, because no consistent write order observed by all threads. Dekker
fails, because release stores followed by loads may or may not be
visible in program order:

                     volatile int x; volatile int y;
-----------------------------------------------------------------------
    putRelease(x, 1);            |    putRelease(y, 1);
    r1 = getAcquire(y);          |    r2 = getAcquire(x);

(r1, r2) = (0, 0) is allowed. Forbidden if all ops are volatile.


Safe construction still does not work (even for volatiles!):

                                A global;
-----------------------------------------------------------------------
    A a = <alloc>;                  |  A a = global;
    put{Release|Volatile}(a.x, 1);  |  r1 = get{Acquire|Volatile}(a.x);
    global = a;                     |

(r1) = (0) is allowed.


> 2) If I want a happens-before relationship before a write and a read:
> Consider two variables X and Y. I first store a value 'a' in X and then
> a value 'b' to Y. I want to make sure that if a thread reads 'b' from Y,
> the 'a' value of X will be visible to this thread.
> The usual and "supported" way to go is to have Y be a volatile variable
> and perform volatile loads and stores to Y.

See the first example above.

> However, wouldn't it be enough to simply perform an ordered store and a
> volatile load?

Two answers:
 a) Yes, unless you need sequential consistency;
 b) No, unless you can give up sequential consistency;

> In java 9, would it also be enough to perform a release store
> (putObjectRelease) and an acquire load (getObjectAcquire)?

Same two answers.

The bottom-line is that acq/rel are very sharp tools, and their
advantages overcome the maintainability/reasoning downsides only in a
few selected cases and/or on weak memory model hardware platforms that
do not have fast SC primitives.

Thanks,
-Aleksey

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20160504/cec501d9/attachment.bin>


More information about the Concurrency-interest mailing list