[concurrency-interest] AtomicReference.updateAndGet() mandatory updating

Hans Boehm boehm at acm.org
Tue May 30 14:23:32 EDT 2017


The memory model does not define "the memory consistency effects of a
write". It only defines the effect of a volatile write to a specific field;
the "memory consistency effects" depend entirely on the location being
written. The problem here is that there normally is no write to associate
the "memory consistency effect" with.

I think the question essentially comes down to which of the following are
performed atomically by a CAS:

(CAS classic:)
old = x;
if (old == expected) {
    x = new; return true;
} else {
    return false;
}

or

(CAS revised:)
old = x;
x = (old == expected ? new : x);
return old == expected;

>From my perspective, there are many architectures that matter, but the two
I expect to be the most widely used with the Java language in the
appropriate time frame are x86 and ARMv8.  (Depending on your metric,
perhaps in the other order.) ARMv8 CAS will use LDAX/STRX rather than
fences. I expect Android's Java language runtime to generate fences (mostly
DMB ISHST) essentially only at the end of constructors, though we're not
quite there yet.

I'm not convinced this decision matters significantly in terms of
programmability. Alex convinced me that it is, unfortunately, observable,
because there are examples in which you can deduce that code is  after a
failed CAS. There may be code that relies on it, but I've never personally
seen such code in production.

On x86, I think this decision doesn't matter for performance; the
implementation is the same either way, and "CAS revised" won't really write
to x in the failure case.

On ARMv8, it does matter. I think Andrew is right that we can replace the
actual assignment on failure with a conditionally executed fence on failure
to avoid adding contention on failure. (This is another case in which a
more careful correctness argument is clearly called for.) But I believe
that requires an additional branch and a fence, making it less attractive
to inline the CAS. And certainly it slows down the failure path when the
LDAX reads the wrong value, and the release operation would normally be
omitted. In the absence of contention, I'd expect the slowdown for the
failure path to be roughly a factor of two now, and perhaps more as the
implementations evolve.

C++ clearly specifies "CAS classic". There is no way to specify release
semantics for a failed CAS, since there is no write.

On Tue, May 30, 2017 at 7:06 AM, Doug Lea <dl at cs.oswego.edu> wrote:

>
> Catching up...
>
> On 05/26/2017 04:08 PM, Nathan and Ila Reynolds wrote:
> >> "The memory effects of a write occur regardless of outcome."
> >> "This method has memory effects of at least one volatile read and
> write."
> >
> > I am not sure what memory effects means.  If this is defined somewhere
> > in the specs, then ignore this since I haven't read JDK 9 specs.
>
> Thanks; it would be better to say:
> "The memory consistency effects of a write occur regardless of outcome."
>
> About the controversy surrounding ARM mappings for Volatile-mode CAS:
> The main underlying intent is to ensure that Volatile mode operations
> act atomically and as if globally totally ordered wrt each other.
> With single instruction CAS (as on x86 etc), this is easy to arrange.
> Plus there are cases like CAS of thread-confined variables in which,
> in principle they could be optimized to conditional stores; plus other
> similar weakenings. In the absence of weakening, when emulated using
> ARM/POWER LL/SC, this further interacts with whether implementations
> use trailing-fence vs leading-fence conventions. If using trailing
> fence (which most if not all Java implementations do), then it seems
> that the only good decision is to issue a fence on comparison failure;
> perhaps differently depending on whether using AArch64 LDAX/STRX
> vs explicit fences inside CAS loop.
>
> At least some C/C++ ARM and POWER mappings use leading-fence
> convention, which could lead to differences here. Also, there
> are version of C++ compare_exchange_strong that take a second
> memory_order argument controlling the consistency effects on
> failure (by default seq_cst/volatile). Although implementations
> elide fence here only on comparison failure, not on contention
> failure. There's no Java equivalent, so people would need to
> use one of the weak variants and add fences.
>
> -Doug
>
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170530/c1acaff7/attachment-0001.html>


More information about the Concurrency-interest mailing list