10

I have found in this site some interesting questions (e.g., this one) about the visibility effects of volatile variables in Java originated from this paragraph taken from the book Java concurrency in Practice:

The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable. So from a memory visibility perspective, writing a volatile variable is like exiting a synchronized block and reading a volatile variable is like entering a synchronized block.

There is, however, an scenario that is not completely clear for me even after reading the answers to related questions in this site, concretely:

What would be the effects of a thread A0 writing to the same volatile variable before the thread A? In other words: A0 writes the volatile variable, this value is later overwritten by A (which does not read the variable) and afterwards read by B. (so we have two write operations from different threads (A0 and A) and a read operation from a third thread (B)).

Can I safely assume that both A and B are guaranteed to see everything that was visible to A0 before A0 wrote to the volatile variable?

UPDATE:

This is a conceptual question about the Java memory model. I know that I cannot predict the order in which writes to the volatile variable occurs in threads A0 and A and the read in thread B. However, just for the sake of facilitating the discussion, lets say that A0 starts lots of time before A does it, and after another significant amount of time B starts, and lets make the simplifying assumption that this is enough to guarantee that the writes and reads happen in the described order (I know that the order cannot be guaranteed by timing only, this is just a simplification in order to avoid diverging from the original question).

Community
  • 1
  • 1
Sergio
  • 8,532
  • 11
  • 52
  • 94
  • volatile variable just makes sure that reader will read latest value but wont guarantee avoidance of race condition. – SMA Jan 25 '15 at 18:07
  • Yes. That's exactly the same rule, with B replaced by A0. – JB Nizet Jan 25 '15 at 18:07
  • What do you mean by "with B replaced by A0" @JBNizet ? Is my assumption correct or not? Thanks for the clarification! – Sergio Jan 25 '15 at 18:40
  • Interesting question. I'm stuck on what exactly "everything" means? Does "everything" mean all the other variables that may exist on the object that owns the volatile var? Does it mean a non-volatile object that thread A0 has access to and is cached in thread A's context but not cached in thread B's context? – Jose Martinez Jan 26 '15 at 02:25
  • 1
    @JoseMartinez everything means shared variables among the three threads which may be volatile as well as non-volatile. – veritas Jan 26 '15 at 04:18

4 Answers4

3

Can I safely assume that both A and B are guaranteed to see everything that was visible to A0 before A0 wrote to the volatile variable?

Writing to a volatile doesn't give a thread any happens-before guarantees about reads.

When B reads, it will see anything A0 could see provided it sees the update it makes. B can also see anything A could see provided it sees the value A wrote. Otherwise B could see state older than either thread if the value it reads didn't come from that thread i.e. it was too early.

If A0 attempts to write first, it might complete after A e.g. say A is on the same socket as the clean copy of the data. It can get access to it before A0 as the later will take longer to acquire the cache line. It is the one which finishes last which determines the eventual state of the data.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I am not sure if I fully understand your answer. I know that thread B could see anything that A0 could see provided that it sees the update A0 made to the variable. But my question is: what happens if the value written by A0 was overwritten by A before B reads the value (so B will actually see the value written by A, not A0). Can B still see everything that A0 could see? and in this case can A see everything that A0 could see? I tried to rephrase a bit my question to make it more clear what is the exact scenario I have doubts about. – Sergio Jan 25 '15 at 18:50
  • If B sees a value after an update A0 made, B will see anything at least as current as A0 could see. The fact A updated the same information doesn't matter. A doesn't see what A0 could see as it doesn't read the volatile variable. – Peter Lawrey Jan 25 '15 at 20:39
  • What do you mean with 'it sees the update it makes'? In the code example in my answer, B does not 'see' the update from A0 (the value written by A0), but does synchronize with it. – Ishtar Jan 25 '15 at 20:45
  • @Ishtar You are right that B will see any values A could read and any non-volatile values it wrote before writing to the volatile variable. – Peter Lawrey Jan 25 '15 at 20:48
  • @Ishtar your Thread B only synchronizes with thread A and sees value of Threas A0 because your thread A synchronizes with Thread A0 – veritas Jan 25 '15 at 23:05
  • Peter, if I understood correctly you say that under my scenario thread B is guaranteed to see both what A0 and A could see. This seems to contradict the answer of @veritas. Could you clarify? – Sergio Jan 26 '15 at 01:33
  • @Sergio "guarantees ... could" doesn't make sense. B and only B is guaranteed to see what A0 and A could read if it reads after they write. There is no guarantees between A and A0 not even ordering of the write. – Peter Lawrey Jan 26 '15 at 10:35
  • @Sergio there is a big problem with your question. You say in the updated section “*I know that the order cannot be guaranteed by timing only*”, but actually ask about a scenario that only makes sense if we assume that timing was a thing. If a thread reads a `volatile` variable that has been been written by two threads, there is no way for the reading thread to detect that both writes have happened. The specification clearly states that there is a *happens-before* relationship between the write and the thread *subsequently reading that value*, not for the write whose value has never been read. – Holger Jan 19 '18 at 12:21
3

I think the scenario is very simple.

A0 - write to volatile variable V value WA0

A - write to volatile variable V value WA

Now

Can I safely assume that both A and B are guaranteed to see everything that was visible to A0 before A0 wrote to the volatile variable?

if Thread A is only writing to V , then it may or may not see the everything that was visible to A0 before the write to V.

Its only if Thread A reads the variable V and the value it reads turns out to be WA0, only then thread A is guaranteed to see everything visible to A0 before it wrote to V.

The same goes with Thread B it depends which value B sees after reading the value of V.

if B reads the value to V to be WA then it will see all which happened before the write of V in Thread A.

if B reads the value to V to be WA0 then it will see all which happened before the write of V in thread A0.

Also please keep in the mind that

Thread A0 

  a = 1;   // non volatile write 
  V = WA0; // volatile write 

Thread A;
  a=3
  V = WA;  // volatile write 


Thread B;
  while(V == 'WA') {
    assert(a,3); // This may fail
  }

You need to understand the code in thread b is incorrectly synchronized volatile gives guarantees related to visibility and reordering, but not of atomicity.

So even if thread B reads value of V to be 'WA' and its guarantee to see everything which happened in thread A before write to V, it doesn't necessarily means that it will see the value of a as 3, because it very well could happened that after reading value of V as WA thread A0 writes to a as 1 which becomes to available to Thread B and thus making your assertion fail. Happens before guarantees you that everything which must happens before a write to v is already happened but its doesn't mean you can't see the future values. You can easily reproduce the scenario by doing something like that

Thread B;
      while(V == 'WA') {
        Thread.sleep(1000);
        assert(a,3); // This may fail
      }

Therefore these scenarios Single Writer is preferable or you program should not have code like the above in thread B because then you have data race in your program.

EDIT :

Example Modified:

Thread 1 (T1)

   a = 1; // normal write
   b = 1; // normal write
   v = 1; // volatile write 

Thread 2 (T2)

   a = 2; // normal write
   c = 2; // normal write
   v = 2; // volatile write   

Thread 3  (T3)

  while(true) {
     if(v == 2) {

       assert (c == 2); //  will pass
       assert (b == 1); //  may fail if T1 hasn't run till
       assert (a == 2); //  may fail if T1 has run and set the value to 1
       break;
     }   
     if(v == 1) {
       assert (b == 1); // will pass
       assert (c == 2); // may fail if T2 hasn't run till
       assert (a == 1); // may fail if T2 has now run setting a == 2 
       break; 
     }
  }

" for the sake of facilitating the discussion, lets say that A0 starts lots of time before A does it, and after another significant amount of time B starts." as OP states

Now if i restate the above statement as (v == 1 happens before (hb) v == 2 ) .

i.e i assume i have a guarantee that v==1 hb (v==2)

Then behavior of Thread 3 will be changed as

Thread 3 (T3)

  while(true) {
     if(v == 2) {

       assert (c == 2); //  will pass
       assert (b == 1); //  will pass
       assert (a == 2); //  will pass
       break;
     }   
     if(v == 1) {
       assert (b == 1); // will pass
       assert (c == 2); // may fail if T2 hasn't run till
       assert (a == 1); // may fail if T2 has now run setting a == 2 
       break; 
     }
  }

The problem with the above behavior is how would you guarantee that

v==1 hb (v==2)

I think if you can understand how to establish the above guarantee then you would have answer to your question yourself.

one way is to establish the way @ishrat did in Thread A. There are other ways too in jmm.

but that guarantee can not be achieved by time alone, you need to rely on the underlying guarantees of language spec and platform you are working on.

also please read this excellent article about jmm

veritas
  • 2,444
  • 1
  • 21
  • 30
  • The value read is irrelevant? I can't find any reference for why the value matters.. – Ishtar Jan 25 '15 at 20:47
  • So you mean that B, after reading the volatile variable, could see everything that was visible to A but there is no guarantee that B could see everything that was visible to A0? This seems contradictory to the answer of @lshtar, where he says that B should see everything that was visible to both A0 and A (in the scenario where A overwrites the value originally written by A0). But I am not sure if I misunderstood something. – Sergio Jan 25 '15 at 20:55
  • @Ishtar see http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5. we need two actions to establish happens before . the second action is the read of that value in this case – veritas Jan 25 '15 at 22:52
  • @sergio you are assuming A0 executed before Thread A. Assume First Threa A executed then Then thread B executed and when Thread B finds the condition V == 'WA' immediately after that Thread A0 executed, then you can establish the race – veritas Jan 25 '15 at 22:54
  • yes, a fundamental assumption of my question is that A0 writes the volatile value before A writes it. The code shown by @lshtar illustrates the exact scenario. Under that assumption is correct the answer of @lshtar? – Sergio Jan 25 '15 at 23:42
  • @sergio You can never determine which thread has set the value first. So you cannot make this assumption in your code. Unless of course you stop the progress of Thread A unless Thread A0 has set the value, similar to what Ishtar has done by using while loop in Thread A. – veritas Jan 25 '15 at 23:50
  • I know I cannot determine the order. I am just trying to understand the subtle aspects of the Java memory model and all the rules that govern volatile variables. Note that I do not have any code actually implementing the scenario, my question was originated after reading the paragraph from the book I mentioned. – Sergio Jan 25 '15 at 23:54
  • java concurrency in practice doesn't give much insights. Its a great book but its just the tip of the iceberg. Please read through this blog http://shipilev.net/blog/2014/jmm-pragmatics/ . It will probably clear your doubts. Also read about Sequential Consistency then you can easily relate java memory model – veritas Jan 25 '15 at 23:55
  • Thanks. I conclude from your answers that under the assumption that A0 writes the volatile variable before A does it, the answer of @lshtar is correct. – Sergio Jan 26 '15 at 00:00
  • @veritas. I mean ''Its only if Thread A reads the variable V and the value it reads turns out to be WA0, only then thread A is guaranteed to see everything visible to A0 before it wrote to V'' should be ''Its only if Thread A reads the variable V only then thread A is guaranteed to see everything visible to A0 before it wrote to V''. And similar for B. There is a hb, regardless of the value read, if the read is later in synchronization order. Of course reading the value written, implies that synchronization order. But it is not a necessary, in this conceptual question, as the order is given. – Ishtar Jan 26 '15 at 16:05
  • @Ishtar No Ishtar that's a wrong statement, suppose if you read V in thread A and the value turns out to be some xyz, then how can you conclude the it will see everything visible to A0 before it wrote to V, its doesn't even gaurantees that if A0 has written anything V. You can easily imagine the scenario if there is one more thread (X) writing to V, then how would you determine What is visible to A ? everything visible to A0 or everything visible to X. – veritas Jan 26 '15 at 17:13
  • " as the order is given." i think this is the main problem - actually you are assuming something which itself doesn't have correct root. Therefore all reasoning will fell flat. If you go into implementation details then it might be what you say is true. But implementation of JMM can change very easily tomorrow any compiler optimization or processor with weak memory order can break that. We need to stick to the rules specified by the language – veritas Jan 26 '15 at 17:16
  • @veritas. Sergio is not asking about 'the main problem'. In the updated question, the synchronization order is given. (Sergio acknowlegdes the fact that it is conceptual.) The JLS (the rules of the language) clearly states that in that synchronization order, there is a hb from the read to both writes, *regardless* of the value read. – Ishtar Jan 27 '15 at 21:46
  • @Ishtar yes that's what i have answered. see my answer for Thread T3 where i have incorporated that assumption. – veritas Jan 27 '15 at 21:53
  • @Ishtar: if you assume that “the synchronization order is given” then it is complete nonsense to discuss about what the `volatile` reads and write do as the hb relationship is already there, just as a premise of the question as “the synchronization order is given”. You could discuss a hypothetical scenario where you enforce a synchronization order without establishing a hb relationship to add that hb using volatile variables afterwards but since the JMM doesn’t offer such a scenario, it’s pointless. – Holger Jan 28 '15 at 20:04
0

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). JLS 17.4.4

Thus, the write from A0 synchronizes with the read from B. All earlier writes from A0 happens before the following reads from B. If there are no other writes to these variables, then yes, B must see them.

I can't find that A synchronizes with A0. So, no guarantees on the visibility in A.

From the updated question, we have the following execution, where A0, A1 and B are threads, t0,t1,t2 are statements and writeV,readV are writes/reads to volatile V:

A0             A1              B
t0 <-- writeV     
         ^     t1 <-- writeV    
         |              ^
         |              \------readV <-- t2
         \-----------------------/

Arrows denote happensbefore. We have t0 and t1 happensbefore t2. t2 will see the updates from t0 and t1.

Thus, yes: B is guaranteed to see everything written by A0 in t0. And it will read the volatile value written by A.

But not t0 happensbefore t, nor vice versa. Thus, no: A is not guaranteed to see everything written by A0.

However, this is only conceptual, in real life B can not know if A0 executed at all.

Ishtar
  • 11,542
  • 1
  • 25
  • 31
  • So you mean that B, after reading the volatile variable, could see everything that was visible to both A0 and A before their write to the volatile variable BUT there is no guarantee that A could see everything that was visible to A0? The first part seems contradictory to the answer of @veritas, where he says that B will see everything that was visible to A, but not A0 (in the scenario where A overwrites the value originally written by A0). But I am not sure if I misunderstood something. – Sergio Jan 25 '15 at 20:48
  • @Sergio. If you could post some code, I'll tell you what executions are allowed / possible. B sees writes of A and A0 (or later writes). A and A0 could and may not see each others writes. Unless they synchronize somehow, code plz ;) – Ishtar Jan 25 '15 at 21:22
  • @Ishtar your this statement is wrong "B does not have to 'see the update' to see the other writes". In your example you have already establish that V = WA implies V = WA0 that's why You assert in B will not fail . its already a chained happens before. if you remove while loop in Thread A, Your assert in Thread B will fail. – veritas Jan 25 '15 at 22:59
  • @ishtar its a simple rule if A hb B and B hb C then it implies A hb C. – veritas Jan 25 '15 at 23:00
  • lshtar thanks for your answer. I understand what you say but my only concern is that it seems to contradict the answer of @veritas and I do not know anymore who is right :( (I am thankful to both for your help independently of who is right). – Sergio Jan 25 '15 at 23:35
  • @lshtar, just realised that the example you provided is incorrect since Thread A is both reading and writing the volatile variable. The question was about what happens if A just writes on the variable (it does not read it). What changes in your answer under that fix? Please clarify. – Sergio Jan 26 '15 at 01:22
  • @Sergio. Indeed, thanks! I removed the example. Clarified and adopted to the updated question. – Ishtar Jan 26 '15 at 15:48
0

Can I safely assume that both A and B are guaranteed to see everything that was visible to A0 before A0 wrote to the volatile variable?

No. With volatile stores the happens-before edge is built when there is a predicate involved. For instance, in order for thread A to see all writes done by A0's write it needs assert on the volatile write.

int a,b;
volatile c;
A0:
 a = 10;
 b = 5;
 c = 20;
A:
 if(c == 20){
    // here all writes by A0 are guaranteed to be visible (ie: a and b).
    c = 50;
 }

If we introduce a third thread B similar checks would need to be done:

int a,b;
volatile c;
A0:
 a = 10;
 b = 5;
 c = 20;
A:
 if(c == 20){ 
    c = 50;
 }

B:
  if(c == 50){
    // B will see all writes done by A and also A0.
  } 

So the guarantee you are looking for is associated with these happens-before edges defined by a write and subsequent read.

Otherwise, thread A and B can read a, b, and c as either their default values 0 or the values written to.

However, for the sake of facilitating the discussion, lets say that A0 starts lots of time before A does it, and after another significant amount of time B starts.

In practice you probably won't run into memory issues, but you should never write your software with that thought ahead of time.

Also, I doubt you meant it this way, but if you truly mean start - The writes of one thread happens-before the starting of another thread (the start happening within the same thread).


Edit for your comment.

If we remove the read from A but keep the read from B in place the possible values are for each thread are

int a,b;
volatile c;
A0:
 a = 10;
 b = 5;
 c = 20;
A:
 int l = c; // c could be either 20 or 0
 int j = a; // a could be either 10 or 0
 int k = b; // b could be either 5 or 0
 c = 50;

B:
  if(c == 50){
     int l = c; // c can be 20 or 50. c cannot be 0
     int j = a; // a could be either 10 or 0
     int k = b; // b could be either 5 or 0
  } 

As you can see there is no relationship between the writes of thread A0 and the reads/writes of A or B unless we have the read pre-condition.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • Thanks for your answer John. Could you please update your example taking into consideration that thread A does not read the volatile variable? I have just updated my question to emphasise that this is the scenario I am asking about. – Sergio Jan 26 '15 at 17:29
  • 1
    @JohnVint l=c is not guaranteed to be 50 in thread B, there is data race. A0 (c=20) can just execute after the if condition is evaluated to true in thread B. You need more than happens before to gaurantee l=c to be 50 – veritas Jan 27 '15 at 02:15