15

I try to understand why this example is a correctly synchronized program:

a - volatile
Thread1:
x=a
Thread2:
a=5

Because there are conflicting accesses (there is a write to and read of a) so in every sequential consistency execution must be happens-before relation between that accesses. Suppose one of sequential execution:

1. x=a
2. a=5

Is 1 happens-before 2, why?

user2394937
  • 161
  • 4
  • 1
    You refer to a program, but I can only see pseudo-code being not meaningful at all. – home May 17 '13 at 17:58
  • 3
    Am I the only one , to whom the question is not clear – stinepike May 17 '13 at 17:59
  • how come all of the answers on this question are so hard to understand. isn't this supposed to be a site where things are explained clearly? – KyleM May 17 '13 at 18:39

4 Answers4

12

Is 1 happens-before 2, why?

I'm not 100% sure I understand your question.

If you have a volatile variable a and one thread is reading from it and another is writing to it, the order of those accesses can be in either order. It is a race condition. What is guaranteed by the JVM and the Java Memory Model (JMM) depends on which operation happens first.

The write could have just happened and the read sees the updated value. Or the write could happen after the read. So x could be either 5 or the previous value of a.

every sequential consistency execution must be happens-before relation between that accesses

I'm not sure what this means so I'll try to be specific. The "happens before relation" with volatile means that all previous memory writes to a volatile variable prior to a read of the same variable are guaranteed to have finished. But this guarantee in no way explains the timing between the two volatile operations which is subject to the race condition. The reader is guaranteed to have seen the write, but only if the write happened before the read.

You might think this is a pretty weak guarantee, but in threads, whose performance is dramatically improved by using local CPU cache, reading the value of a field might come from a cached memory segment instead of central memory. The guarantee is critical to ensure that the local thread memory is invalidated and updated when a volatile read occurs so that threads can share data appropriately.

Again, the JVM and the JMM guarantee that if you are reading from a volatile field a, then any writes to the same field that have happened before the read, will be seen by it -- the value written will be properly published and visible to the reading thread. However, this guarantee in no way determines the ordering. It doesn't say that the write has to happen before the read.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • this was not mine, but i suspect that because smb thinks that data race and race condition are the same things. it will be great if u extend answer with defining the difference between this definitions. in fact this means that in the example there is a race condition but no data race. So thats valid jmm execution. https://blog.regehr.org/archives/490 here is more detailed explanation about these terms – Stepan Pogosyan May 21 '19 at 14:30
  • I'm no sure I understand your point @StepanPogosyan. A "data race" is a race condition with data. I highly disagree with the blog post which talks about race conditions as some "external timing or ordering". Wikipedia makes no distinction for example: https://en.wikipedia.org/wiki/Race_condition . Multithreaded programs are by design asynchronous. We mostly want it this way since the independency of the threads is what gives us parallel execution and performance improvements. Anytime 2 threads share data there can be race conditions. – Gray May 22 '19 at 15:46
  • 1
    I've added some more details to my answer. – Gray May 22 '19 at 15:53
  • i was talking about data race according to jmm and data race which means nondetermined execution. Lets take example from the head of this topic: { a - volatile Thread1: x=a Thread2: a=5 } This execution have no data races according to jmm cause we have hb relation and know that we can read only two values of a here: 0 or 5. But according to academic data race definition (wiki :D) there is nondetermenism here and we cant predict exactly before the execution what we will read. How to mitigate this collision and distinguish these definitions? – Stepan Pogosyan Jun 04 '19 at 16:33
  • finally think im close to truth. Ive just had to read jmm more carefully. According to JMM data race is "When a program contains two conflicting accesses (§17.4.1) that are not ordered by a happens-before relationship, it is said to contain a data race." (https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5). – Stepan Pogosyan Jun 04 '19 at 17:53
  • And race condition (according to academic papers) means that the correctness of the program (the satisfaction of postconditions and invariants) depends on the relative timing of events in concurrent computations A and B (http://web.mit.edu/6.031/www/fa17/classes/19-concurrency/#race_condition). So i think these are two different definitions from this point of view. And the example in the head do not have data races but have race condition. – Stepan Pogosyan Jun 04 '19 at 17:53
  • 1
    It seems that data race is just the subset of race condition in case of sharing memory conflicts. And race condition is more general definition which also includes execution order conflict and may be more. – Stepan Pogosyan Jun 04 '19 at 18:10
  • Yes to the final comment. This is a race-condition because of execution order between 2 threads accessing data. – Gray Jun 05 '19 at 16:00
6

No, a volatile read before (in synchronization order) a volatile write of the same variable does not necessarily happens-before the volatile write.

This means they can be in a "data race", because they are "conflicting accesses not ordered by a happens-before relationship". If that's true pretty much all programs contain data races:) But it's probably a spec bug. A volatile read and write should never be considered a data race. If all variables in a program are volatile, all executions are trivially sequentially consistent. see http://cs.oswego.edu/pipermail/concurrency-interest/2012-January/008927.html

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
1

Sorry, but you cannot say correctly how the JVM will optimize the code depending on the 'memory model' of the JVM. You have to use the high level tools of Java for defining what you want.

So volatile means only that there will be no "inter-thread cache" used for the variables.

If you want a stricter order, you have to use synchronized blocks.

http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html

xtraclass
  • 445
  • 3
  • 7
1

Volatile and happens-before is only useful when the read of the field drives some condition. For example:

volatile int a;
int b =0;
Thread-1:
   b = 5;
   a = 10;
Thread-2
   c = b + a;

In this case there is no happens-before, a can be either 10 or 0 and b can be either 5 or 0, so as a result c could be either 0, 5, 10 or 15. If the read of a implies some other condition then the happens-before is established for instance:

int b = 0;
volatile int a = 0;
Thread-1:
   b = 5
   a = 10;
Thread 2: 
   if(a == 10){
      c = b + a;
   }

In this case you will ensure c = 15 because the read of a==10 implies that the write of b = 5 happens-before the write of a = 10

Edit: Updating addition order as noted the inconsistency by Gray

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • 1
    @Gray I guess my point is that without some kind of predicate there is no happens-before relationship. Hence my first example. However in this case it is guaranteed to be 15 the former it can range from any number within (0, 5, 10, 15). In my latter example, if a is not volatile then c could be 10 or 15. – John Vint May 17 '13 at 20:43
  • 3
    Wait, actually the first part is slightly incorrect. There is no way c can be 10. If a is 10, b has to be 5. That _is_ the happens-before. b could be 0 or 5 but if a is 10, b has to be 5. – Gray May 17 '13 at 20:50
  • 1
    Good point, if I switch the addition from `c = a + b` to `c = b + a` then the my example is more accurate. But you're right, the first part only can be either 15, 0 or 5 if a is read before b. – John Vint May 17 '13 at 20:56