Quantcast

AtomicReference get vs. getAcquire; get/set Opaque

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

AtomicReference get vs. getAcquire; get/set Opaque

Dávid Karnok
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)? More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)



--
Best regards,
David Karnok

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Martin Buchholz-3


On Sat, Sep 24, 2016 at 6:19 AM, Dávid Karnok <[hidden email]> wrote:
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)?

Yes, but ... the poll and offer operations will no longer be part of the global sequentially consistent order of synchronization actions.

More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

 
In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)

I think there is a difference on x86.  Conceptually, set/volatile write "drains the write buffer", while setRelease does not.


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Vitaly Davidovich


On Saturday, September 24, 2016, Martin Buchholz <[hidden email]> wrote:


On Sat, Sep 24, 2016 at 6:19 AM, Dávid Karnok <<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;akarnokd@gmail.com&#39;);" target="_blank">akarnokd@...> wrote:
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)?

Yes, but ... the poll and offer operations will no longer be part of the global sequentially consistent order of synchronization actions.
How so? 

Volatile load (get()) prevents subsequent stores and loads from moving above it - so does getAcquire. 

lazySet never really had a formal definition, certainly wasn't part of JMM.  Most people assumed it ensured prior stores didn't move past the lazySet - nothing more.  setRelease appears to prevent prior loads and stores from moving past it.  Given lazySet delegates to setRelease, it would imply that lazySet also didn't allow prior loads to move past it, not just stores.

So talking about the global synchronization order when there was already lazySet, rather than volatile store, seems iffy.

More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

 
In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?
I've asked for more explanation of opaque before, not sure that's happened.  In particular, it's unclear if atomicity is guaranteed (e.g. load/store a long on 32bit archs).  It would seem it's mirroring memory_order_relaxed in C++ otherwise.

For the single queue in this thread, it's unclear if it would work.  An object published via setOpaque may have its stores happen after since no ordering, other than program, is guaranteed - CPU can reorder internally though.

One way to think about the opaque operations is to pretend they happen inside a method the JIT didn't inline.  It therefore cannot optimize across it because it doesn't know if the method would invalidate its operations.  So it's kind of a full compiler fence in that sense.

My personal impression is that opaque is useful for ensuring atomicity of a read/store only, like the memory_order_relaxed in C++, although the atomicity hasn't been clarified, AFAIK.

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)

I think there is a difference on x86.  Conceptually, set/volatile write "drains the write buffer", while setRelease does not.
Minor nit: nothing "drains the write buffer" - normal CPU machinery drains it on its own.  What the volatile set would end up doing is preventing subsequent instructions from executing until the store buffer is drained.  So it's a pipeline bubble/hazard.




--
Sent from my phone

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Alex Otenko
In reply to this post by Martin Buchholz-3
In the documentation for getAcquire / setRelease there is not a word about ordering of getAcquire and setRelease between themselves.

So it’d be important to know if a subsequent getAcquire can be reordered with a preceding setRelease - eg will polling this queue twice in a loop return the same v.

Alex

On 24 Sep 2016, at 18:10, Martin Buchholz <[hidden email]> wrote:



On Sat, Sep 24, 2016 at 6:19 AM, Dávid Karnok <[hidden email]> wrote:
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)?

Yes, but ... the poll and offer operations will no longer be part of the global sequentially consistent order of synchronization actions.

More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

 
In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)

I think there is a difference on x86.  Conceptually, set/volatile write "drains the write buffer", while setRelease does not.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Martin Buchholz-3
We know the docs could be better, but we do have
"""Ignoring the many semantic differences from C and C++, this method has memory ordering effects compatible with memory_order_acquire ordering."""
http://download.java.net/java/jdk9/docs/api/java/lang/invoke/VarHandle.html#getAcquire-java.lang.Object...-

On Sat, Sep 24, 2016 at 2:34 PM, Alex Otenko <[hidden email]> wrote:
In the documentation for getAcquire / setRelease there is not a word about ordering of getAcquire and setRelease between themselves.

So it’d be important to know if a subsequent getAcquire can be reordered with a preceding setRelease - eg will polling this queue twice in a loop return the same v.

Alex

On 24 Sep 2016, at 18:10, Martin Buchholz <[hidden email]> wrote:



On Sat, Sep 24, 2016 at 6:19 AM, Dávid Karnok <[hidden email]> wrote:
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)?

Yes, but ... the poll and offer operations will no longer be part of the global sequentially consistent order of synchronization actions.

More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

 
In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)

I think there is a difference on x86.  Conceptually, set/volatile write "drains the write buffer", while setRelease does not.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Vitaly Davidovich
In reply to this post by Alex Otenko


On Saturday, September 24, 2016, Alex Otenko <[hidden email]> wrote:
In the documentation for getAcquire / setRelease there is not a word about ordering of getAcquire and setRelease between themselves.

So it’d be important to know if a subsequent getAcquire can be reordered with a preceding setRelease - eg will polling this queue twice in a loop return the same v.
That would violate normal data dependence, wouldn't it? However, a good question is can compiler perform store-load forwarding, yielding null on the second read.  I suspect no because I'd expect acquire/release to encompass opaque as well, and so compiler must perform the read on 2nd iteration. 

Alex

On 24 Sep 2016, at 18:10, Martin Buchholz <<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;martinrb@google.com&#39;);" target="_blank">martinrb@...> wrote:



On Sat, Sep 24, 2016 at 6:19 AM, Dávid Karnok <<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;akarnokd@gmail.com&#39;);" target="_blank">akarnokd@...> wrote:
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)?

Yes, but ... the poll and offer operations will no longer be part of the global sequentially consistent order of synchronization actions.

More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

 
In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)

I think there is a difference on x86.  Conceptually, set/volatile write "drains the write buffer", while setRelease does not.

_______________________________________________
Concurrency-interest mailing list
<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;Concurrency-interest@cs.oswego.edu&#39;);" target="_blank">Concurrency-interest@cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



--
Sent from my phone

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Alex Otenko
Well, knowing there are architectures where data dependencies have to be enforced, it’s hard to tell how far we relax the ordering. There is a reference to C++, and that does clarify what ordering is meant.


Alex


On 25 Sep 2016, at 00:24, Vitaly Davidovich <[hidden email]> wrote:



On Saturday, September 24, 2016, Alex Otenko <[hidden email]> wrote:
In the documentation for getAcquire / setRelease there is not a word about ordering of getAcquire and setRelease between themselves.

So it’d be important to know if a subsequent getAcquire can be reordered with a preceding setRelease - eg will polling this queue twice in a loop return the same v.
That would violate normal data dependence, wouldn't it? However, a good question is can compiler perform store-load forwarding, yielding null on the second read.  I suspect no because I'd expect acquire/release to encompass opaque as well, and so compiler must perform the read on 2nd iteration. 

Alex

On 24 Sep 2016, at 18:10, Martin Buchholz <[hidden email]> wrote:



On Sat, Sep 24, 2016 at 6:19 AM, Dávid Karnok <[hidden email]> wrote:
I have a one element single-producer single-consumer "queue" implemented as this:

boolean offer(AtomicReference<T> ref, T value) {
    Objects.requireNonNull(value);
    if (ref.get() == null) {
        ref.lazySet(value);
        return true;
    }
    return false;
}

T poll(AtomicReference<T> ref) {
    T v = ref.get();
    if (v != null) {
       ref.lazySet(null);
    }
    return v;
}

Is it okay to turn get() into getAcquire() and lazySet into setRelease() (I can see lazySet delegates to setRelease)? 

Yes, but ... the poll and offer operations will no longer be part of the global sequentially consistent order of synchronization actions.

More generally, are there consequences turning CAS loops of get()+compareAndSet into getAcquire() + weakCompareAndSetRelease?

 
In addition, are there examples (or explanations) of when it is okay to use getOpaque/setOpaque  and would they work with the concurrent "queue" above at all?

(I guess there is not much difference for x86 but my code may end up on weaker platforms eventually.)

I think there is a difference on x86.  Conceptually, set/volatile write "drains the write buffer", while setRelease does not.

_______________________________________________
Concurrency-interest mailing list
Concurrency-interest@cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



-- 
Sent from my phone


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: AtomicReference get vs. getAcquire; get/set Opaque

Aleksey Shipilev-3
In reply to this post by Dávid Karnok
On 09/24/2016 03:19 PM, Dávid Karnok wrote:

> I have a one element single-producer single-consumer "queue" implemented
> as this:
>
> boolean offer(AtomicReference<T> ref, T value) {
>     Objects.requireNonNull(value);
>     if (ref.get() == null) {
>         ref.lazySet(value);
>         return true;
>     }
>     return false;
> }
>
> T poll(AtomicReference<T> ref) {
>     T v = ref.get();
>     if (v != null) {
>        ref.lazySet(null);
>     }
>     return v;
> }
>
> Is it okay to turn get() into getAcquire() and lazySet into setRelease()
> (I can see lazySet delegates to setRelease)?
Replacing {get,set}Volatile with {get,set}Acquire/Release is generally
not okay, as you will relax the sequential consistency. See:
 http://cs.oswego.edu/pipermail/concurrency-interest/2016-May/015104.html
 http://cs.oswego.edu/pipermail/concurrency-interest/2016-March/015037.html

SPSC is more forgiving, and it _appears_ fine to replace with
getAcq/setRel in this example: a) you can publish the value correctly
through setRelease/getAcquire chain; b) you will never observe null in
offer() before poll() pulls the value, since there are WAR data
dependencies between get and lazySet on the same variable.


> In addition, are there examples (or explanations) of when it is okay to
> use getOpaque/setOpaque  and would they work with the concurrent "queue"
> above at all?

It is almost never okay to replace {get,set}{Volatile,Acquire,Release}
with {get,set}Opaque. Opaque does NOT guarantee ANY inter-thread ordering.


Thanks,
-Aleksey



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

signature.asc (836 bytes) Download Attachment
Loading...