3

While going through Java Concurrency in practice by Brian Goetz I encountered the following line:

A data race occurs when a variable is read by more than one thread, and written by at least one thread, but the reads and writes are not ordered by happens-before. A correctly synchronized program is one with no data races; correctly synchronized programs exhibit sequential consistency, meaning that all actions within the program appear to happen in a fixed, global order.

My Question is that, Is Out of Order writes the only reason for Data Race condition in java or possibly in other programming languages?
UPDATE
OK, I did some more investigation about data-race and found the following from oracle official site which says that :

The Thread Analyzer detects data-races that occur during the execution of a multi-threaded process. A data race occurs when:

  • two or more threads in a single process access the same memory location concurrently, and
  • at least one of the accesses is for writing, and
  • the threads are not using any exclusive locks to control their accesses to that memory.

When these three conditions hold, the order of accesses is non-deterministic, and the computation may give different results from run to run depending on that order. Some data-races may be benign (for example, when the memory access is used for a busy-wait), but many data-races are bugs in the program.


In this part, it is mentioning that : the order of accesses is non-deterministic
Is it talking about the the sequence in which Threads are accessing the memory location? If yes, then synchronization never guarantee about the order in which threads will access the block of code. So , how synchronization can resolve the issue of data race?

Mac
  • 1,711
  • 3
  • 12
  • 26
  • I think that's pretty much the definition of data race, yes. – biziclop Jul 05 '14 at 23:27
  • @biziclop: Thanks for your response, So it means that say only one variable is being accessed by the multiple threads and one of the threads is writing to that variable atomically while rest of the threads are accessing it concurrently then there can't be any data-race condition over there? – Mac Jul 05 '14 at 23:34
  • 2
    Yes there can. The problem there is memory visibility. Unless you have marked the variable as volatile or are protecting its access with either synchronized block or lock, it is possible that a given thread will not see updates made by another thread. – Brett Okken Jul 05 '14 at 23:37
  • @BrettOkken : Thanks . Does it means that Data Race is all about atomicity , Sequencing (of order of codes in block of code being executed by Threads **not of Threads execution** )as well as visibility? If all of these are implemented correctly then there can't be data race condition within that code? – Mac Jul 05 '14 at 23:44
  • 1
    @Mac: _writing to that variable atomically_ is the key. The atomic operations supported by Java (e.g. `java.util.concurrent.atomic.*`) guarantees that the operations are ordered. So if one thread updates an atomic variable, the update **happens-before** all subsequent reads. The atomic operation itself sets the memory barrier. If you can not update the variable atomically (or with synchronization or locks), then cases like mentioned in @BrettOkken 's comment could happen – James Jul 05 '14 at 23:47
  • http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5 – Alex - GlassEditor.com Jul 05 '14 at 23:52
  • 1
    @Mac: it's all about memory barrier. Atomic operation, visibility, synchronization and locks are all about setting a memory barrier so that operations on particular blocks of data have proper ordering semantics. – James Jul 05 '14 at 23:53
  • People who are voting to close this question please put your comment so that I can know why you think that I am unclear about what I am asking here. If you want any clarification regarding this question then ask me. I will be more than happy to elaborate the concern that I want to raise in this question. – Mac Jul 05 '14 at 23:59
  • 2
    We need to be careful talking about atomic operations. Setting any primitive (other than double or long) is atomic. That does not mean it is visible across threads. – Brett Okken Jul 06 '14 at 00:03
  • @BrettOkken: Thanks for bringing out this point. I think the atomic Setting of double and long can be resolved by declaring them as volatile. – Mac Jul 06 '14 at 00:17
  • And marking them as volatile also creates a memory barrier and establishes happens before relationships (as with any other data type being marked as volatile). – Brett Okken Jul 06 '14 at 00:49
  • Brian Goetz: "A correctly synchronized program is one with no data races." Oracle: "Some data-races may be benign." These two sources define "data race" differently. Oracle's definition is broader. There are myriad ways in which the operations performed by the threads of a large multi-threaded program can be interleaved. Oracle says there's a data race when different interleavings can lead to different output. Goetz only calls it a data race when some interleavings lead to _wrong_ output (including crashes, data corruption, or maybe just isolated wrong answers.) – Solomon Slow Jul 06 '14 at 01:29
  • 1
    @jameslarge The two aren't necessarily conflicting. Some data races may indeed be benign, but the program would still be classed as not correctly synchronized. – biziclop Jul 06 '14 at 16:29
  • 1
    @Mac People who are voting to close this question clearly take the stance that if they don't understand it, it can't make any sense. Unfortunately SO has too many of these sorts of people Your question is of course perfectly clear and valid. – biziclop Jul 06 '14 at 16:30
  • 1
    I think there's a lot of confusion both in this question and the comments. Specifically, the notion of nondeterministic access order by different threads (which is *always* present) is being confused with violation of *causality* between actions of threads. – Marko Topolnik Jul 06 '14 at 18:53
  • The question itself contains confused assumptions as well: `Is Out of Order writes the only reason for Data Race condition?` Out-of-order writes happen with or without data races. They are definitely not a *reason* for data races; however the presence of data races means that out-of-order writes can be observed by other threads, breaking causality. – Marko Topolnik Jul 06 '14 at 18:57
  • So the question should be, "are data races dangerous only due to out-of-order writes?" and the answer to that one is: no, there are many other reasons as well, such as *writes not happening at all*. A non-volatile variable's value may be copied to the stack, all subsequent writes within a method going to that copy. – Marko Topolnik Jul 06 '14 at 19:00
  • @MarkoTopolnik: Thanks for putting your thought on this question. But as you can see in the questions I have put the words exactly as told in the book "*A data race occurs when a variable is read by more than one thread, and written by at least one thread, but the **reads and writes are not ordered by happens-before**.*" I think it is clearly mentioning that if reads and writes are not ordered by happens-before then there will be the race condition. Please correct me if I am wrong : *out of order writes is the one culprit which is responsible for not following the happens before relationship*. – Mac Jul 06 '14 at 19:25
  • @MarkoTopolnik :As you have mentioned in your comment *Out-of-order writes happen with or without data races*. However, I am asking it just the other way around : *Does data races happens with or without Out-of-order writes?* – Mac Jul 06 '14 at 19:33
  • You are confusing levels of description: ordering by *happens-before* is 1) a static property of a program and 2) more abstract than the notion of out-of-order writes. A program can contain a data race even if no out-of-order write ever occurs in its execution. – Marko Topolnik Jul 06 '14 at 19:36
  • @MarkoTopolnik: Then What is the real cause of Data Race in java? And what causes the read and writes to not to be ordered by happens before? – Mac Jul 06 '14 at 19:38
  • Well, that's what the JLS clearly specifies. You have read the chapter on Memory Model, haven't you? – Marko Topolnik Jul 06 '14 at 19:45
  • As mentioned in JLS about data race: *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.* And about happens before relationship : *Two actions can be ordered by a happens-before :if one action happens-before another, then the first is visible to and ordered before the second.*. Ultimately data race boils down to happens-before order. And as per my understanding for two actions x and y if x happens before y then anyone(thread) after reading the action y should see the action x also. Am I right? – Mac Jul 06 '14 at 19:54
  • Yes, that's right. It's about causality. And the static property of a correctly syncronized program is that all conflicting inter-thread actions will have *some* happens-before ordering between them. Which exactly will happen before which other is non-deterministic, of course. – Marko Topolnik Jul 06 '14 at 20:05
  • Thanks @MarkoTopolnik : Now, if I have correctly reached that far in understanding the happens-before then let me put a snapshot of what I have understood about data race: *data-race=>happens-before ordering not followed=>out of order writes happened in code*. Is it correct? Also if you look in JLS for this line **Table 17.2. Surprising results caused by statement reordering - valid compiler transformation** . Just below it is written that *This situation is an example of a data race* – Mac Jul 06 '14 at 20:13
  • No, the step from "no happens-before ordering" to "out-of-order writes happening" is not that simple. First of all, there may have been only *one* write, so clearly it cannot be out-of-order with itself; yet another thread may never observe it without a happens-before. Second, out-of-order writes may not happen at all, they just become *allowed* by the JLS. Third, as I mentioned earlier, many other things may happen which do not boil down to out-of-order writes---such as no writes at all. – Marko Topolnik Jul 06 '14 at 20:18
  • @MarkoTopolnik : So, going by that can I understand the sequence in this way : *data-race=>happens-before ordering not followed=> either or few or all of the following had happened: 1. out-of-order writes 2. local cache is thread is not updated 3. write hasn't happened till now.* – Mac Jul 06 '14 at 20:26
  • A data race exists in a program *by definition*. Nothing bad must actually happen and in a naïve JVM implementation, nothing will---execution may proceed in a sequentially consistent manner and no inter-thread actions will be perceived out of order even in a program completely lacking any syncronization. – Marko Topolnik Jul 06 '14 at 23:15
  • @MarkoTopolnik Thanks for your effort that you brought in to clarify the concept about Data Race. Would you please like to provide your insight on my following question too: http://stackoverflow.com/questions/40340317/why-liskov-substitution-principle-needs-the-argument-to-be-contravariant – Mac Oct 31 '16 at 11:39

1 Answers1

1

I would rather define data race as

Data race between writing and reading of some value or reference from a variable is a situation when the result of reading is determined by the "internal" (jvm- or os-controlled) thread scheduling.

In fact, second definition from the question says the same in more "official" words :)

In the other words, consider thread A writing some value to the variable and thread B attempting to read it. If you miss any kind of synchronization (or other mechanism that can provide happens-before guarantees between write and subsequent read), your program has a data race between threads A and B.

Now, to your question:

Is it talking about the the sequence in which Threads are accessing the memory location? If yes, then synchronization never guarantee about the order in which threads will access the block of code.

Synchronization in that particular case guarantees that you will never be able to read value that variable had before the writer thread written new value after writer thread exited synchronized block or method. Without syncronization, there is a chance to read old value even after write is actually happened.

About the order of access: it is going to be deterministic with synchronization in the following way:

Let's take a look at our threads A and B again. The operations order is now sequential - thread B will not be able to start reading until thread A finished with writing. To get this situation clear, imagine that writing and reading is really a long process. Without synchronization, these operations will be able to interlap with each other which might result in some meaningless values read.

Alexey Malev
  • 6,408
  • 4
  • 34
  • 52