I'm having problems understanding how JMM relates to possible instructions reordering. For example, let's consider the following code snippet:
volatile boolean t1HasArrived = false, t2HasArrived = false;
// In thread 1
t1HasArrived = true;
while (!t2HasArrived)
;
// In thread 2
t2HasArrived = true;
while (!t1HasArrived)
;
Now, I want to believe that this code implements Barrier synchronization for two threads. But I'm not sure about it. The thing that gives me doubts is read/writes reordering: is there anything in JMM that would prevent compiler or CPU to rearrange execution path of the code like the code snippet below? And if not, how do you actually prove that such reordering is allowed?
// In thread 1
while (!t2HasArrived)
;
t1HasArrived = true;
// In thread 2
while (!t1HasArrived)
;
t2HasArrived = true;
Note, that I'm not trying to implement locks-free Barrier. This is just an example that came to my mind after I started thinking about instructions reordering. I just want to understand how to apply JMM rules to it. It is relatively easy to reason about piece of code when there is only one volatile variable/lock involved, but when there are several, things become complicated.
Volatile variables cannot be reordered with each other by the JMM.
In your case, you have a volatile store followed by a volatile load, and those cannot be reordered into a load followed by a store. This is true for all versions of Java.
See The JSR-133 Cookbook for Compiler Writers for specifics.
Lasciate ogni speranza, voi ch’entrate.
From the JSR-133 specification:
Inter-thread Actions An inter-thread action is an action performed by one thread that can be detected or directly influenced by another thread. Inter-thread actions include reads and writes of shared variables and synchronization actions, such as locking or unlocking a monitor, reading or writing a volatile variable, or starting a thread.
Synchronization Actions Synchronization actions include locks, unlocks, reads of and writes to volatile variables, actions that start a thread, and actions that detect that a thread is done.
We only consider well-formed executions. An execution E = 〈P, A, po→, so→, W, V, sw→, hb→〉 is well formed if the following conditions are true:
- Synchronization order is consistent with program order and mutual exclusion. Having synchronization order is consistent with program order implies that the happensbefore order, given by the transitive closure of synchronizes-with edges and program order, is a valid partial order: reflexive, transitive and antisymmetric. Having synchronization order consistent with mutual exclusion means that on each monitor, the lock and unlock actions are correctly nested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With