LockSupport park/unpark and memory visibility

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

LockSupport park/unpark and memory visibility

Anthony Maire
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

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

Re: LockSupport park/unpark and memory visibility

Henri Tremblay
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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: LockSupport park/unpark and memory visibility

Vitaly Davidovich
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

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

Re: LockSupport park/unpark and memory visibility

Tom Lee
In reply to this post by Henri Tremblay
On Tue, Nov 15, 2016 at 11:45 AM, Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Nor am I, so forgive any lies that follow. :)
 
Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park

To the best of my knowledge, lazySet on x86 is roughly equivalent to

mov [dest], src

(i.e. write to memory location dest the value from some register src)

That write eventually makes its way into the executing CPU's store buffer. Eventually that write will become visible as the store buffer flushes out, but exactly when may not be entirely deterministic.

"Normal" volatile writes (e.g. writing to a volatile instance variable, or calling AtomicBoolean.set()) will add an additional instruction after the mov (iirc usually a lock xchg) that forces the CPU to wait until the store buffer has completely flushed before proceeding. So you "know" that the value written will be visible to all CPUs performing a read before anything else happens on the CPU doing the write. Put another way, the lock xchg enforces a happens-before relationship on a CPU.
 
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

I don't believe unpark is a fence, but I could be wrong -- I'll leave that to others. On the assumption that it isn't, either ready needs to be volatile or it needs to be an AtomicBoolean written with set() (N.B. lazySet is not what you want, because the store buffer may not flush before you unpark threadA & it will go right back to sleep again).

And of course, all this ignores JIT/compiler reordering, and other archetectures may be more or less strict with respect to lazySet. To be safe, I imagine you'd typically want to combine lazySets with volatile writes to give yourself some better guarantees. Personally I've never had cause to worry about that sort of thing, but it's fun to think about how it all works.

Hope all this makes sense and/or is free from gross misinformation. :)

Cheers,
Tom


Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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: LockSupport park/unpark and memory visibility

Vitaly Davidovich


On Tue, Nov 15, 2016 at 3:23 PM, Tom Lee <[hidden email]> wrote:
On Tue, Nov 15, 2016 at 11:45 AM, Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Nor am I, so forgive any lies that follow. :)
 
Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park

To the best of my knowledge, lazySet on x86 is roughly equivalent to

mov [dest], src

(i.e. write to memory location dest the value from some register src)

That write eventually makes its way into the executing CPU's store buffer. Eventually that write will become visible as the store buffer flushes out, but exactly when may not be entirely deterministic.

"Normal" volatile writes (e.g. writing to a volatile instance variable, or calling AtomicBoolean.set()) will add an additional instruction after the mov (iirc usually a lock xchg) that forces the CPU to wait until the store buffer has completely flushed before proceeding. So you "know" that the value written will be visible to all CPUs performing a read before anything else happens on the CPU doing the write. Put another way, the lock xchg enforces a happens-before relationship on a CPU.
Current (Hotspot in Java 8) incarnation does a lock'd add of 0 to %rsp.  Aleksey Shipilev did some study of various flavors of the fence: https://shipilev.net/blog/2014/on-the-fence-with-dependencies/

And yes, for x86, lazySet is just a mov (+ compiler barrier preventing prior stores from moving after the lazySet store).
 
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

I don't believe unpark is a fence, but I could be wrong -- I'll leave that to others. On the assumption that it isn't, either ready needs to be volatile or it needs to be an AtomicBoolean written with set() (N.B. lazySet is not what you want, because the store buffer may not flush before you unpark threadA & it will go right back to sleep again).
AFAICT, LockSupport park or unpark have no memory order definition.  As mentioned in my earlier reply, Dave Dice said you should pretend park/unpark are empty methods and then consider whether your synchronization is still sound.  In Oracle/OpenJDK, the native parker impl will have instructions causing fences, but that's an implementation detail.

With lazySet then, if you pretend that unpark() does a normal store, then there's nothing preventing that store in unpark() from floating above the store to 'ready'.

And of course, all this ignores JIT/compiler reordering, and other archetectures may be more or less strict with respect to lazySet. To be safe, I imagine you'd typically want to combine lazySets with volatile writes to give yourself some better guarantees. Personally I've never had cause to worry about that sort of thing, but it's fun to think about how it all works.

Hope all this makes sense and/or is free from gross misinformation. :)

Cheers,
Tom


Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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



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

Re: LockSupport park/unpark and memory visibility

Alex Otenko
In reply to this post by Anthony Maire
Normally there will be more - you’d need to tell who is waiting. For illustrative purposes (not that this makes sense in the presence of multiple waiters):

threadA: if (!ready) {waiter = Thread.currentThread; while(!ready) {LockSupport.park();}}

threadB: ready = true; if (waiter != null) {waiter = null; LockSupport.unpark(w);}

The parts in bold need to be a Dekker idiom, otherwise you won’t wake up some waiters. So waiter and ready need to be volatile.

In the presence of multiple waiters waiter will be a list with thread-safe add, poll, remove, but the essence is the same - adding or removing a waiter to/from the list is at least a volatile-store.

Then the barriers inside park/unpark do not matter.


Alex


On 15 Nov 2016, at 14:34, Anthony Maire <[hidden email]> wrote:

Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.
_______________________________________________
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: LockSupport park/unpark and memory visibility

Anthony Maire
In reply to this post by Vitaly Davidovich
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

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

Re: LockSupport park/unpark and memory visibility

Anthony Maire
In reply to this post by Alex Otenko
In fact, the structure I'm working on is guaranteed to have at most a single waiter so the full code is more like this one (although in the current version I have, setting the waiter to null was done in the waiter code after exiting the wait loop, but that is only temporary code until I have more information on LS usage)

However, I don't understand how this guarantee that we have no possible issue, even when the volatile write to the waiter field in threadB. This write is not observed so it is not guaranteed to have any memory effect according to https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#wishful-unobserved-volatiles.

Could you please explain further ?

Regards,
Anthony

2016-11-16 8:51 GMT+01:00 Alex Otenko <[hidden email]>:
Normally there will be more - you’d need to tell who is waiting. For illustrative purposes (not that this makes sense in the presence of multiple waiters):

threadA: if (!ready) {waiter = Thread.currentThread; while(!ready) {LockSupport.park();}}

threadB: ready = true; if (waiter != null) {waiter = null; LockSupport.unpark(w);}

The parts in bold need to be a Dekker idiom, otherwise you won’t wake up some waiters. So waiter and ready need to be volatile.

In the presence of multiple waiters waiter will be a list with thread-safe add, poll, remove, but the essence is the same - adding or removing a waiter to/from the list is at least a volatile-store.

Then the barriers inside park/unpark do not matter.


Alex


On 15 Nov 2016, at 14:34, Anthony Maire <[hidden email]> wrote:

Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.
_______________________________________________
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: LockSupport park/unpark and memory visibility

Alex Otenko
There are several issues with that example. One of them is that even if the barriers were not eliminated, they could still be reordered with the reads and the writes to x and y - that code isn’t an example of correct synchronization even if the same Holder instance were used by both actors.

I am not sure what your question is about waiter store and load. The important aspect is that threadA must indicate that it decided to enter park, and for threadB to check that indicator - be it a volatile boolean flag or a volatile reference to a Thread. If your code isn’t doing that, you are likely losing out more by always calling park/unpark than you win by eliminating that volatile indicator, unless you want to bet on a particular JVM that perhaps reduces the cost of park/unpark to less than a volatile store/load.


Besides, after return from park you better check whether the Thread was interrupted. I think there are implementations that will not “park” until you checked (thus cleared) that flag, if it happens to be set - so the interrupted threadA will burn CPU by ignoring the interrupted flag check.


Alex

On 16 Nov 2016, at 10:27, Anthony Maire <[hidden email]> wrote:

In fact, the structure I'm working on is guaranteed to have at most a single waiter so the full code is more like this one (although in the current version I have, setting the waiter to null was done in the waiter code after exiting the wait loop, but that is only temporary code until I have more information on LS usage)

However, I don't understand how this guarantee that we have no possible issue, even when the volatile write to the waiter field in threadB. This write is not observed so it is not guaranteed to have any memory effect according to https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#wishful-unobserved-volatiles.

Could you please explain further ?

Regards,
Anthony

2016-11-16 8:51 GMT+01:00 Alex Otenko <[hidden email]>:
Normally there will be more - you’d need to tell who is waiting. For illustrative purposes (not that this makes sense in the presence of multiple waiters):

threadA: if (!ready) {waiter = Thread.currentThread; while(!ready) {LockSupport.park();}}

threadB: ready = true; if (waiter != null) {waiter = null; LockSupport.unpark(w);}

The parts in bold need to be a Dekker idiom, otherwise you won’t wake up some waiters. So waiter and ready need to be volatile.

In the presence of multiple waiters waiter will be a list with thread-safe add, poll, remove, but the essence is the same - adding or removing a waiter to/from the list is at least a volatile-store.

Then the barriers inside park/unpark do not matter.


Alex


On 15 Nov 2016, at 14:34, Anthony Maire <[hidden email]> wrote:

Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.
_______________________________________________
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: LockSupport park/unpark and memory visibility

Vitaly Davidovich
In reply to this post by Anthony Maire
Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

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

Re: LockSupport park/unpark and memory visibility

Alex Otenko
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.

Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

--
Sent from my phone
_______________________________________________
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: LockSupport park/unpark and memory visibility

Vitaly Davidovich
This would be a particular implementation detail. Since we're hypothesizing, it's possible that unpark() can use an unordered read (i.e. relaxed) as an optimization, and then we're back to same situation.

Either way though, this thread and previous ones on LS are indication that more documentation is needed.

On Wed, Nov 16, 2016 at 7:35 AM Alex Otenko <[hidden email]> wrote:
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.


Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

--
Sent from my phone
_______________________________________________
Concurrency-interest mailing list
[hidden email]
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
|

Re: LockSupport park/unpark and memory visibility

Viktor Klang
Since we're talking about something which is un(der)-specced, what use is it to speculate in what horrors could happen? ^^

The only way to make sure is to add the appropriate belt-and-suspenders around it to make sure that there's something which provides the desired semantics :)

On Wed, Nov 16, 2016 at 1:45 PM, Vitaly Davidovich <[hidden email]> wrote:
This would be a particular implementation detail. Since we're hypothesizing, it's possible that unpark() can use an unordered read (i.e. relaxed) as an optimization, and then we're back to same situation.

Either way though, this thread and previous ones on LS are indication that more documentation is needed.

On Wed, Nov 16, 2016 at 7:35 AM Alex Otenko <[hidden email]> wrote:
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.


Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

--
Sent from my phone
_______________________________________________
Concurrency-interest mailing list
[hidden email]
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




--
Cheers,

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

Re: LockSupport park/unpark and memory visibility

Doug Lea
In reply to this post by Vitaly Davidovich

On 11/16/2016 07:45 AM, Vitaly Davidovich wrote:
> This would be a particular implementation detail. Since we're
> hypothesizing, it's possible that unpark() can use an unordered read
> (i.e. relaxed) as an optimization, and then we're back to same situation.
>
> Either way though, this thread and previous ones on LS are indication
> that more documentation is needed.

We do already say in the javadocs:

"Reliable usage requires the use of volatile (or atomic) variables to
control when to park or unpark."

Some people familiar with the implementation on some JVM might wish we
would promise more, but (1) the specs are designed to allow other
implementations, even including park() as no-op; (2) as nicely
explained by Alex Otenko, a stronger spec shouldn't impact how you
use it anyway.

-Doug




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

Re: LockSupport park/unpark and memory visibility

Vitaly Davidovich
In reply to this post by Viktor Klang
Right, nobody really wants to speculate but lacking specs/docs, that's all that's left :).

IMO, a component meant as a low-level concurrency building block deserves extensive/sufficient specs. Knowing what properties are provided by the building block (vs what user needs to add themselves) may have performance implications. There's really no room for guessing/speculation here.

On Wed, Nov 16, 2016 at 7:57 AM Viktor Klang <[hidden email]> wrote:
Since we're talking about something which is un(der)-specced, what use is it to speculate in what horrors could happen? ^^

The only way to make sure is to add the appropriate belt-and-suspenders around it to make sure that there's something which provides the desired semantics :)

On Wed, Nov 16, 2016 at 1:45 PM, Vitaly Davidovich <[hidden email]> wrote:
This would be a particular implementation detail. Since we're hypothesizing, it's possible that unpark() can use an unordered read (i.e. relaxed) as an optimization, and then we're back to same situation.

Either way though, this thread and previous ones on LS are indication that more documentation is needed.

On Wed, Nov 16, 2016 at 7:35 AM Alex Otenko <[hidden email]> wrote:
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.


Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

--
Sent from my phone
_______________________________________________
Concurrency-interest mailing list
[hidden email]
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




--
Cheers,
--
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
|

Re: LockSupport park/unpark and memory visibility

Alex Otenko
In reply to this post by Vitaly Davidovich
It is not just an “implementation detail”. It is also a minimal sensible implementation.

How about this: park enter/exit and unpark appear in synchronization order, but only guarantee park exit occurs for every park enter, if there are unpark events after the preceding park exit in that order - no new synchronizes-with edges. This is pretty much all that park-unpark can be reasonably expected to do, and the minimal requirement.


Alex


On 16 Nov 2016, at 12:45, Vitaly Davidovich <[hidden email]> wrote:

This would be a particular implementation detail. Since we're hypothesizing, it's possible that unpark() can use an unordered read (i.e. relaxed) as an optimization, and then we're back to same situation.

Either way though, this thread and previous ones on LS are indication that more documentation is needed.

On Wed, Nov 16, 2016 at 7:35 AM Alex Otenko <[hidden email]> wrote:
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.


Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

--
Sent from my phone
_______________________________________________
Concurrency-interest mailing list
[hidden email]
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
|

Re: LockSupport park/unpark and memory visibility

Vitaly Davidovich
In reply to this post by Doug Lea
Doug,

It's still not clear. Can you explain what in the current docs states that unpark() cannot move above a volatile store? How about a lazySet/ordered put? Is that considered "atomically" or not?

On Wed, Nov 16, 2016 at 8:15 AM Doug Lea <[hidden email]> wrote:

On 11/16/2016 07:45 AM, Vitaly Davidovich wrote:
> This would be a particular implementation detail. Since we're
> hypothesizing, it's possible that unpark() can use an unordered read
> (i.e. relaxed) as an optimization, and then we're back to same situation.
>
> Either way though, this thread and previous ones on LS are indication
> that more documentation is needed.

We do already say in the javadocs:

"Reliable usage requires the use of volatile (or atomic) variables to
control when to park or unpark."

Some people familiar with the implementation on some JVM might wish we
would promise more, but (1) the specs are designed to allow other
implementations, even including park() as no-op; (2) as nicely
explained by Alex Otenko, a stronger spec shouldn't impact how you
use it anyway.

-Doug




_______________________________________________
Concurrency-interest mailing list
[hidden email]
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
|

Re: LockSupport park/unpark and memory visibility

Vitaly Davidovich
In reply to this post by Alex Otenko
unpark can also unconditionally set a flag, with a relaxed store, with no ordered load. Since park is allowed to return spuriously "for no reason at all", I don't see how that isn't allowed (whether it's sensible or not is a separate topic).

And as I mentioned to Doug, is lazySet considered using "atomics" or not?

On Wed, Nov 16, 2016 at 8:15 AM Alex Otenko <[hidden email]> wrote:
It is not just an “implementation detail”. It is also a minimal sensible implementation.

How about this: park enter/exit and unpark appear in synchronization order, but only guarantee park exit occurs for every park enter, if there are unpark events after the preceding park exit in that order - no new synchronizes-with edges. This is pretty much all that park-unpark can be reasonably expected to do, and the minimal requirement.


Alex


On 16 Nov 2016, at 12:45, Vitaly Davidovich <[hidden email]> wrote:

This would be a particular implementation detail. Since we're hypothesizing, it's possible that unpark() can use an unordered read (i.e. relaxed) as an optimization, and then we're back to same situation.

Either way though, this thread and previous ones on LS are indication that more documentation is needed.

On Wed, Nov 16, 2016 at 7:35 AM Alex Otenko <[hidden email]> wrote:
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.


Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

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

--
Sent from my phone

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

Re: LockSupport park/unpark and memory visibility

Anthony Maire
In reply to this post by Alex Otenko
for threadA indicating that it is entering the park loop and threadB collecting that information to know which thread to unpark, it is something that I already have in my code, but I didn't include it in my original question ...
My point is not on how to make sure that threadB will actually call unpark on the right thread, but on how to be sure that when unparked threadA will correctly see the write that will allow to exit from the park loop.

For the interruption part, for the moment, I have a big "//TODO: handle interruption" at the beginning of the class :) Thank you for the additional information, it will be helpful.

2016-11-16 13:17 GMT+01:00 Alex Otenko <[hidden email]>:
There are several issues with that example. One of them is that even if the barriers were not eliminated, they could still be reordered with the reads and the writes to x and y - that code isn’t an example of correct synchronization even if the same Holder instance were used by both actors.

I am not sure what your question is about waiter store and load. The important aspect is that threadA must indicate that it decided to enter park, and for threadB to check that indicator - be it a volatile boolean flag or a volatile reference to a Thread. If your code isn’t doing that, you are likely losing out more by always calling park/unpark than you win by eliminating that volatile indicator, unless you want to bet on a particular JVM that perhaps reduces the cost of park/unpark to less than a volatile store/load.


Besides, after return from park you better check whether the Thread was interrupted. I think there are implementations that will not “park” until you checked (thus cleared) that flag, if it happens to be set - so the interrupted threadA will burn CPU by ignoring the interrupted flag check.


Alex

On 16 Nov 2016, at 10:27, Anthony Maire <[hidden email]> wrote:

In fact, the structure I'm working on is guaranteed to have at most a single waiter so the full code is more like this one (although in the current version I have, setting the waiter to null was done in the waiter code after exiting the wait loop, but that is only temporary code until I have more information on LS usage)

However, I don't understand how this guarantee that we have no possible issue, even when the volatile write to the waiter field in threadB. This write is not observed so it is not guaranteed to have any memory effect according to https://shipilev.net/blog/2016/close-encounters-of-jmm-kind/#wishful-unobserved-volatiles.

Could you please explain further ?

Regards,
Anthony

2016-11-16 8:51 GMT+01:00 Alex Otenko <[hidden email]>:
Normally there will be more - you’d need to tell who is waiting. For illustrative purposes (not that this makes sense in the presence of multiple waiters):

threadA: if (!ready) {waiter = Thread.currentThread; while(!ready) {LockSupport.park();}}

threadB: ready = true; if (waiter != null) {waiter = null; LockSupport.unpark(w);}

The parts in bold need to be a Dekker idiom, otherwise you won’t wake up some waiters. So waiter and ready need to be volatile.

In the presence of multiple waiters waiter will be a list with thread-safe add, poll, remove, but the essence is the same - adding or removing a waiter to/from the list is at least a volatile-store.

Then the barriers inside park/unpark do not matter.


Alex


On 15 Nov 2016, at 14:34, Anthony Maire <[hidden email]> wrote:

Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.
_______________________________________________
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: LockSupport park/unpark and memory visibility

Alex Otenko
In reply to this post by Vitaly Davidovich
Perfectly good example of why park/unpark should be disconnected from synchronizes-with edges. Plugging them in synchronization order gives you that guarantee about "reordering" park/unpark with preceding/following volatile accesses.

Alex

On 16 Nov 2016, at 13:35, Vitaly Davidovich <[hidden email]> wrote:

unpark can also unconditionally set a flag, with a relaxed store, with no ordered load. Since park is allowed to return spuriously "for no reason at all", I don't see how that isn't allowed (whether it's sensible or not is a separate topic).

And as I mentioned to Doug, is lazySet considered using "atomics" or not?

On Wed, Nov 16, 2016 at 8:15 AM Alex Otenko <[hidden email]> wrote:
It is not just an “implementation detail”. It is also a minimal sensible implementation.

How about this: park enter/exit and unpark appear in synchronization order, but only guarantee park exit occurs for every park enter, if there are unpark events after the preceding park exit in that order - no new synchronizes-with edges. This is pretty much all that park-unpark can be reasonably expected to do, and the minimal requirement.


Alex


On 16 Nov 2016, at 12:45, Vitaly Davidovich <[hidden email]> wrote:

This would be a particular implementation detail. Since we're hypothesizing, it's possible that unpark() can use an unordered read (i.e. relaxed) as an optimization, and then we're back to same situation.

Either way though, this thread and previous ones on LS are indication that more documentation is needed.

On Wed, Nov 16, 2016 at 7:35 AM Alex Otenko <[hidden email]> wrote:
Not necessarily.

unpark can end up just checking a flag to see that the thread has not been parked after some preceding call to unpark. This can make it behave like a volatile load, which will have to be totally ordered with a store in park that clears that flag. So there may be no stores in a particular execution of unpark.


Alex

On 16 Nov 2016, at 12:20, Vitaly Davidovich <[hidden email]> wrote:

Yes, that's the blog entry I was referring to.

So I agree with you that LS ordering is underspecified. Specifically, unpark() must have release semantics to preclude it from moving above the volatile store. Otherwise, as you say, threadA can be unparked before the volatile write is visible and then it'll go back to sleep indefinitely.

Note that a volatile write doesn't change this - if unpark() isn't ordered, it can be moved above the volatile write (theoretically).

On Wed, Nov 16, 2016 at 5:18 AM Anthony Maire <[hidden email]> wrote:
Thank you for that first feedback

for the "the JMM says a write to a volatile field can be seen by all threads." by Henri, the issue is not that the waiter will not see the write, but that it may not see at the precise moment that it has been unparked, so it is parked again and wait possibly forever. As far as I understand it, the JMM is based on HB edges, so to make sure the write is visible at that precise moment, there should be an HB edge between unpark and park, which is not guaranteed
Of course, it will work because the volatile write implies waiting for the store buffer to drain so that write will always be visible for threadA, but it seems an implementation detail to me, so it is not something I want to rely on.

For the FIFOMutex example, I agree that is intended to work (LS will be pretty useless if it doesn't) and it works by experience. But I would like to know why it is guaranteed to works so I can reason about LS easier :)

For the Dave Dice test, I assume that Vitaly is referring to this blog post : https://blogs.oracle.com/dave/entry/a_race_in_locksupport_park
That's basically where my second question about lazySet comes from : it will work with empty methods, but if we assume that park/unpark can have no fences (since the current fences are an implementation detail) it seems even more fragile


2016-11-15 20:55 GMT+01:00 Vitaly Davidovich <[hidden email]>:
The LS javadoc has an example usage, FIFOMutex, that's a similar idiom to Anthony's example. That would imply the idiom is intended to work.

LS on its own isn't spec'd to provide any happens-before/ordering, so user needs to provide that themselves. I recall Dave Dice mentioning that a good litmus test for proper LS usage is to pretend park/unpark are empty methods that degenerate into spinning.

On Tue, Nov 15, 2016 at 2:49 PM Henri Tremblay <[hidden email]> wrote:
I'm not a subject matter expert on this but:

Yes. It works if "ready" is volatile. Because for any implementation, the JMM says a write to a volatile field can be seen by all threads.

An AtomicBoolean would also work on a set().

Two things I don't know:
1- How lazy is lazySet()? I would be afraid that lazySet() might set ready after threadA check its value and is back to park
2- Do "ready" need to be volatile? Or is pack/unpark providing some kind of memory fence.

Henri


On 15 November 2016 at 09:34, Anthony Maire <[hidden email]> wrote:
Hi
Sorry if this has been already asked, but I didn't succeed to find a clear answer
I'm wondering on how memory consistency can be achieved when using LockSupport park() and unpark() methods
As far as I know, there is no explicit guarantee either in LS javadoc or in the JLS, so I assume that the condition to be check should come with its own visibility mechanism since we don't have any HB relationship.


Let's consider the following idiom, "ready" being a volatile boolean field:
- threadA: while(!ready){ LockSupport.park(this); }
- threadB: ready = true; LockSupport.unpark(threadA);

What does make this example work ? Is it possible for threadA to un²park, check the "ready" field without seeing threadB's store and park again ? If I understand the JMM correctly I would say that it is a valid execution order.
On x86 with OpenJDK or Oracle JVM, I assume this works because the volatile store force the store buffer to drain so that threadA will always see the store when the permit is made available by threadB, but is there any guarantee that is not implementation or architecture dependent ?

Same question is we use AtomicBoolean.get() / AtomicBoolean.lazySet() instead of volatile read/write ? I assume that it should be correct on x86 + openJDK, but is there any strong guarantee on this ?

Kind regards.

_______________________________________________
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
--
Sent from my phone

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

--
Sent from my phone

--
Sent from my phone


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