Does 'volatile' guarantee that any thread reads the most recently written value?
Asked Answered
P

3

6

From the book Effective Java:

While the volatile modifier performs no mutual exclusion, it guarantees that any thread that reads the field will see the most recently written value

SO and many other sources claim similar things.

Is this true?

I mean really true, not a close-enough model, or true only on x86, or only in Oracle JVMs, or some definition of "most recently written" that's not the standard English interpretation...

Other sources (SO example) have said that volatile in Java is like acquire/release semantics in C++. Which I think do not offer the guarantee from the quote.

I found that in the JLS 17.4.4 it says "A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order)." But I don't quite understand.

There are quite some sources for and against this, so I'm hoping the answer is able to convince that many of those (on either side) are indeed wrong - for example reference or spec, or counter-example code.

Phosphorus answered 16/3, 2021 at 10:40 Comment(9)
"But I don't quite understand." What don't you understand? The JLS is the most authoritative reference for Java.Rage
@Rage Don't understand whether that sentence means that other threads will immediately see the value, 'synchronizes-with' and 'subsequent' are not clear enough to mePhosphorus
"Is this true?" Yes. A volatile write happens-before a read of the same variable.Landscape
"There are quite some sources for and against this" Please provide the sources against this.Landscape
"Other sources (SO example) have said that volatile in Java is like acquire/release semantics in C++." - Actually, that question asks it, and neither of the answers actually answer that. (The accepted answer effectively says "Here is the C# spec - you work it out!".) That hardly counts as a legitimate source of information.Golgi
You need to read it like this. If a load synchronizes with a particular store (so sees its value), then there is a happens before relation. So certain assumptions can be made about loads/store before the store and after the load. It doesn't say anything about recency.Ordinarily
@Ordinarily Sounds that's what.I got from your answer and it reasonable, thanks. But the answers seem to contradict each other so I'm hesitant to accept one.Phosphorus
I would suggest digging into the meaning of sequential consistency. And also check out the following: jepsen.io/consistency/models/sequential If real time order should be respected, one needs learnability. Also check the link I posted in my answer.Ordinarily
The answers don't need to contradict each other. On a practical level you could say that a read needs to see the most recent write because the only way to proof it didn't read the most recent value would be to hook up special measuring equipment. And the hardware will not postpone reads/writes indefinitely. Only on a theoretical level reads/writes are allowed to be skewed indefinitely.Ordinarily
L
8

Is this true?

I mean really true, not a close-enough model, or true only on x86, or only in Oracle JVMs, or some definition of "most recently written" that's not the standard English interpretation...

Yes, at least in the sense that a correct implementation of Java gives you this guarantee.

Unless you are using some exotic, experimental Java compiler/JVM (*), you can essentially take this as true.

From JLS 17.4.5:

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.


(*) As Stephen C points out, such an exotic implementation that doesn't implement the memory model semantics described in the language spec can't usefully (or even legally) be described as "Java".

Landscape answered 16/3, 2021 at 10:51 Comment(1)
I would say that an exotic Java that didn't behave according to the revised memory model in Java 5 and later is "not Java". And Oracle's lawyers (who guard the use of the Java trademarks) would agree. If a language implementation doesn't pass the JTK compliance tests, you are not allowed to call it Java (™).Golgi
O
3

It is not true. JMM is based on sequential consistency and for sequential consistency real time ordering isn't guaranteed; for that you need linearizability. In other words, reads and writes can be skewed as long as the program order isn't violated (or as long is it can't be proven po was violated).

A read of volatile variable a, needs to see the most recent written value before it in the memory order. But that doesn't imply real time ordering.

Good read about the topic: https://concurrency-interest.altair.cs.oswego.narkive.com/G8KjyUtg/relativity-of-guarantees-provided-by-volatile.

I'll make it concrete:

Imagine there are 2 CPU's and (volatile) variable A with initial value 0. CPU1 does a store A=1 and CPU2 does a load of A. And both CPUs have the cacheline containing A in SHARED state.

The store is first speculatively executed and written to the store buffer; eventually the store commits and retires, but since the stored value is still in the store buffer; it isn't visible yet to the CPU2. Till so far it wasn't required for the cacheline to be in an EXCLUSIVE/MODIFIED state, so the cacheline on CPU2 still contains the old value and hence CPU2 can still read the old value.

So in the real time order, the write of A is ordered before the read of A=0, but in the synchronization order, the write of A=1 is ordered after the read of A=0.

Only when the store leaves the store buffer and wants to enter the L1 cache, the request for ownership (RFO) is send to all other CPU's which set the cacheline containing A to INVALID on CPU2 (RFO prefetching I'll leave out of the discussion). If CPU2 would now read A, it is guaranteed to see A=1 (the request will block till CPU1 has completed the store to the L1 cache).

On acknowledgement of the RFO the cacheline is set to MODIFIED on CPU1 and the store is written to the L1 cache.

So there is a period of time between when the store is executed/retired and when it is visible to another CPU. But the only way to determine this is if you would add special measuring equipment to the CPUs.

I believe a similar delaying effect can happen on the reading side with invalidation queues.

In practice this will not be an issue because store buffers have a limited capacity and need to be drained eventually (so a write can't be invisible indefinitely). So in day to day usage you could say that a volatile read, reads the most recent write.

A java volatile write/read provides release/acquire semantics, but keep in mind that the volatile write/read is stronger than release/acquire semantics. A volatile write/read is sequential consistent and release/acquire semantics isn't.

Ordinarily answered 16/3, 2021 at 12:47 Comment(8)
I think that book was only implying sequential consistency behavior, as denoted by that "any thread", but otherwise I agree with you : the quote is in general wrong.Teteak
What does it mean for a volatile write/read to be sequentially consistent?Paunchy
@PiotrMichalczyk it means that once a thread has seen some value X, all other threads can only see the same X, in the sense that they can't see a "previous" valueTeteak
The ‘once’ implies time and time is not part of the definition of sequential consistency. Reads and writes are allowed to be skewed.Ordinarily
@Ordinarily ok... but how else can I better define the concept of "sequential consistency"? How would you explain it, to make myself more clear may beTeteak
The rules for sequential consistency: a system needs to behave AS IF: (1) there is a total order over all operations (2) a read sees the most recent write before it IN THAT ORDER (3) the total order is consistent with the program order of each of the threads.Ordinarily
You can use the following SCHEMA en.wikipedia.org/wiki/Sequential_consistency#/media/…, but is is critial that none of the CPUs has any sense of a global time because each CPU has its own clock (local time) that runs completely independent of the others, it might speed up and slow down continuously. So global time doesn't have any meaning for them.Ordinarily
So it might very well be that there is a completed write W from CPU0 to shared memory and load R for the same address issued by CPU1, that R sees the value before W. We can't rely on global time to order W and R. In CPU1's reality, R has been performed before W. So reads and writes can skew as long as the program order of each of the threads isn't violated (nobody should be able to prove it was violated).Ordinarily
T
3

The quote per-se is correct in terms of what is tries to prove, but it is incorrect on a broader view.

It tries to make a distinction of sequential consistency and release/acquire semantics, at least in my understanding. The difference is rather "thin" between these two terms, but very important. I have tried to simplify the difference at the beginning of this answer or here.

The author is trying to say that volatile offers that sequential consistency, as implied by that:

"... it guarantees that any thread.."

If you look at the JLS, it has this sentence:

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

The tricky part there is that subsequent and it's meaning, and it has been discussed here. What is really wants to mean is "subsequent that observes that write". So happens-before is guaranteed when the reader observes the value that the writer has written.

This already implies that a write is not necessarily seen on the next read, and this can be the case where speculative execution is allowed. So in this regard, the quote is miss-leading.

The quote that you found:

A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order)

is a complicated to understand without a much broader context. In simple words, it established synchronizes-with order (and implicitly happens-before) between two threads, where volatile v variables is a shared variable. here is an answer where this has broader explanation and thus should make more sense.

Teteak answered 16/3, 2021 at 15:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.