Simulating effects of final fields with memory fences

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
Hello,

I would like to ask the list one concurrency related question. Say you
have a class with a final reference field:

public class X {
     private final Y y;

     public X() {
         y = ...;
     }

     public void m() {
         ... use y ...
     }
}

And that Y is either an immutable or properly synchronized type so "use
y" never has any data races.

Objects of type X can be published via data races, but final modifier on
field y guarantees that the field will never be observed as
uninitialized (null) in method m.

Now say that class X is modified in the following way:

public class X {
     private Y y;

     public X() {
         y = ...;
         VarHandle.storeStoreFence();
     }

     public void m() {
         VarHandle.loadLoadFence();
         ... use y ...
     }
}

- final modifier is removed, storeStoreFence is added as the final
action in constructor, loadLoadFence is added as the first action in method.

Would every guarantee that holds for original class X still hold for
modified class X ?


Thanks, Peter

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

Re: Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
On 06/18/2018 06:12 AM, Peter Levart via Concurrency-interest wrote:

> Hello,
>
> I would like to ask the list one concurrency related question. Say you
> have a class with a final reference field:
>
> public class X {
>     private final Y y;
>
>     public X() {
>         y = ...;
>     }
>
>     public void m() {
>         ... use y ...
>     }
> }
>
> And that Y is either an immutable or properly synchronized type so "use
> y" never has any data races.
>
> Objects of type X can be published via data races, but final modifier on
> field y guarantees that the field will never be observed as
> uninitialized (null) in method m.
>
> Now say that class X is modified in the following way:
>
> public class X {
>     private Y y;
>
>     public X() {
>         y = ...;
>         VarHandle.storeStoreFence();
>     }
>
>     public void m() {
>         VarHandle.loadLoadFence();
>         ... use y ...
>     }
> }

In the most general case, you should use VarHandle.releaseFence()
instead of storeStoreFence. See the discussion of Mixed Modes and
Specializations for Release/Acquire (RA) mode in
http://gee.cs.oswego.edu/dl/html/j9mm.html

-Doug

>
> - final modifier is removed, storeStoreFence is added as the final
> action in constructor, loadLoadFence is added as the first action in
> method.
>
> Would every guarantee that holds for original class X still hold for
> modified class X ?



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

Re: Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
Programming concurrency is hard even when you have sequential consistency as provided by volatile or locks.
If you retreat from that for performance, then go to release paired with acquire, so either VarHandle.releaseFence() and VarHandleAcquireFence() or preferably VarHandle.setRelease() paired with VarHandle.getAcquire(). Going further to storeStoreFence or loadLoadFence is too hard to get right.

On Mon, Jun 18, 2018 at 4:28 AM, Doug Lea via Concurrency-interest <[hidden email]> wrote:
On 06/18/2018 06:12 AM, Peter Levart via Concurrency-interest wrote:
> Hello,
>
> I would like to ask the list one concurrency related question. Say you
> have a class with a final reference field:
>
> public class X {
>     private final Y y;
>
>     public X() {
>         y = ...;
>     }
>
>     public void m() {
>         ... use y ...
>     }
> }
>
> And that Y is either an immutable or properly synchronized type so "use
> y" never has any data races.
>
> Objects of type X can be published via data races, but final modifier on
> field y guarantees that the field will never be observed as
> uninitialized (null) in method m.
>
> Now say that class X is modified in the following way:
>
> public class X {
>     private Y y;
>
>     public X() {
>         y = ...;
>         VarHandle.storeStoreFence();
>     }
>
>     public void m() {
>         VarHandle.loadLoadFence();
>         ... use y ...
>     }
> }

In the most general case, you should use VarHandle.releaseFence()
instead of storeStoreFence. See the discussion of Mixed Modes and
Specializations for Release/Acquire (RA) mode in
http://gee.cs.oswego.edu/dl/html/j9mm.html

-Doug

>
> - final modifier is removed, storeStoreFence is added as the final
> action in constructor, loadLoadFence is added as the first action in
> method.
>
> Would every guarantee that holds for original class X still hold for
> modified class X ?



_______________________________________________
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
|

Re: Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
Hi Martin, Doug,

Thanks for pointer to j9mm.

I understand that for general case, it is advisable to use release / acquire. In particular for cases where constructing a "thread-unsafe" object and publishing it for the receiving end to modify it. You want to be sure that the construction of the object (which may involve writes as well as reads) is "isolated" from later consumption by some other thread that is going to perform reads and writes on it.

But if that object is "thread-safe" - meaning that every access to its internal state (including its construction) is properly synchronized by the object itself, then I would really like to know when the use of storeStoreFence (as the last action in container constructor that constructs the containing object and writes the reference to the object) / loadLoadFence (as the 1st action in a method that dereferences the reference and uses the contained object) can bite me. I really just want to make sure that field 'y' is never seen as null in method m(). Just like it was a primitive field. Is my thinking correct or are there flaws in it?

I'm referring to this code:

public class X {
    private Y y;

    public X() {
        y = ... construct y ...;
        VarHandle.storeStoreFence();
    }

    public void m() {
        VarHandle.loadLoadFence();
        ... use y ...
    }
}


In this code, Y is a class of a "properly synchronized object" which makes sure that it works correctly even if published via data-race.


Regards, Peter


On 06/18/18 15:41, Martin Buchholz via Concurrency-interest wrote:
Programming concurrency is hard even when you have sequential consistency as provided by volatile or locks.
If you retreat from that for performance, then go to release paired with acquire, so either VarHandle.releaseFence() and VarHandleAcquireFence() or preferably VarHandle.setRelease() paired with VarHandle.getAcquire(). Going further to storeStoreFence or loadLoadFence is too hard to get right.

On Mon, Jun 18, 2018 at 4:28 AM, Doug Lea via Concurrency-interest <[hidden email]> wrote:
On 06/18/2018 06:12 AM, Peter Levart via Concurrency-interest wrote:
> Hello,
>
> I would like to ask the list one concurrency related question. Say you
> have a class with a final reference field:
>
> public class X {
>     private final Y y;
>
>     public X() {
>         y = ...;
>     }
>
>     public void m() {
>         ... use y ...
>     }
> }
>
> And that Y is either an immutable or properly synchronized type so "use
> y" never has any data races.
>
> Objects of type X can be published via data races, but final modifier on
> field y guarantees that the field will never be observed as
> uninitialized (null) in method m.
>
> Now say that class X is modified in the following way:
>
> public class X {
>     private Y y;
>
>     public X() {
>         y = ...;
>         VarHandle.storeStoreFence();
>     }
>
>     public void m() {
>         VarHandle.loadLoadFence();
>         ... use y ...
>     }
> }

In the most general case, you should use VarHandle.releaseFence()
instead of storeStoreFence. See the discussion of Mixed Modes and
Specializations for Release/Acquire (RA) mode in
http://gee.cs.oswego.edu/dl/html/j9mm.html

-Doug

>
> - final modifier is removed, storeStoreFence is added as the final
> action in constructor, loadLoadFence is added as the first action in
> method.
>
> Would every guarantee that holds for original class X still hold for
> modified class X ?



_______________________________________________
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


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

Re: Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
On 06/19/2018 03:00 AM, Peter Levart via Concurrency-interest wrote:

> But if that object is "thread-safe" - meaning that every access to its
> internal state (including its construction) is properly synchronized by
> the object itself, then I would really like to know when the use of
> storeStoreFence (as the last action in container constructor that
> constructs the containing object and writes the reference to the object)
> / loadLoadFence (as the 1st action in a method that dereferences the
> reference and uses the contained object) can bite me.

As noted in j9mm doc, the storeStore vs release fence microoptimization
for constructors is based on "nothing need be guaranteed about
interactions with reads by the constructor", which refers to re-reads of
non-final fields (for example a final array ref vs a non-final index),
which would be extended here to pseudo-constructors. Which is usually OK.

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

Re: Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
I got some of my paranoia reading Hans Boehm.  IIRC he discusses storestore somewhere.

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

Re: Simulating effects of final fields with memory fences

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On 06/19/2018 08:00 AM, Peter Levart via Concurrency-interest wrote:

> But if that object is "thread-safe" - meaning that every access to
> its internal state (including its construction) is properly
> synchronized by the object itself, then I would really like to know
> when the use of storeStoreFence (as the last action in container
> constructor that constructs the containing object and writes the
> reference to the object) / loadLoadFence (as the 1st action in a
> method that dereferences the reference and uses the contained
> object) can bite me. I really just want to make sure that field 'y'
> is never seen as null in method m(). Just like it was a primitive
> field. Is my thinking correct or are there flaws in it?

Yes, probably.  What none of us here understand is why you seem to
want to know if it's possible to dance around the rim of the volcano.
Sure, it's possible.  After a lot of arguing, I was persuaded that
StoreStore was enough for a constructor.

--
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest