Saturday, May 29, 2010

Word Tearing

... Or why you are not guaranteed a coherent value when you are reading longs and doubles in Java.

How is that possible?

This mainly due to a language compromise to deal with 'legacy' 32-bit CPU systems, where a 64-bit value memory action is divided into two 32-bit memory actions, which is mainly done for historical efficiency reasons (Refer to 17.4 of the Java Language Specification for an explicit answer to why). But note that this is not a problem if you are using native 64-bit architectures.

So how does this translate to a possible problem?

Lets try to simplify this problem by illustrating the same scenario as having a 2-bit value memory action being split into two 1-bit memory action. So assuming that we have a memory location m which looks something like this:

From the diagram m is logically separated into to two 1-bit locations m[0] and m[1]. Let's assume that m starts off with 00b as its initial value. Then m looks like this:

Now suppose that we have 2 CPUs concurrently executing the following code:


R(m) is a function that reads the value of m, while W(m) is a function that sets the value to m. In the case of our example, CPU1 is reading the value of m while CPU2 is writing the binary value 11b in to m.

Logically if atomicity is enforced, then the only possible value that can be observed at any given time is either 00b or 11b. But in the case of longs and doubles, the specification explicitly mentions that no guarantees of atomicity is enforced.

Hence it is possible to timeslice memory updates in the following order:

As CPU2's execution is timesliced between the execution of CPU1, this results in R(m) return the value of 01b, which is a transient value, but it is not a proper value to be observed.

It can be said that that CPU1 happens to be reading at the right place but at a wrong time. The volatile keyword in Java will resolve this problem, by virtue of the fact that it does not allow reordering of read and write actions, and hence by implictly disallowing read in-between write actions and vice-versa.

This has the effect of making read and write actions appear atomic, not that the read and write actions are implicitly atomic themselves. For a better understanding of what I mean by atomic, see my explanation on the difference between Atomic and Volatile.


Post a comment