[concurrency-interest] Volatile happens before question

Boehm, Hans hans.boehm at hp.com
Wed Jan 18 13:21:05 EST 2012


> From: Raph Frank
> 
> Another question, would this work properly as a lock?
> 
> public class OptimisticLockInt {
> 
>     private int x;
>     private AtomicInteger counter = new AtomicInteger(0);
>     private static final int UNSTABLE = 1;
> 
>     public void set(int x)
>         int oldCount = counter.getAndSet(UNSTABLE);
>         this.x = x;
>         counter.set(oldCount + 2);
>     }
> 
>     public int get() {
>         while (true)
>             int oldCount = counter.getAndSet();
You meant counter.get() here?

>             int tempX = x;
>             if (counter.get() == oldCount) {
>                 return tempX;
>             }
>         }
>     }
> }
> 
> I guess the get() method can be reordered to the following?
> 
>     public int get() {
>         while (true)
>             int oldCount = counter.getAndSet();
>             if (counter.get() == oldCount) {
>                 int tempX = x;
>                 return tempX;
>             } else {
>                 int tempX = x;
>             }
>         }
>     }
> 
Yes.  This is unfortunately incorrect.  This is essentially the Linux seqlock problem.

The obvious fix is to eliminate the data race by making x volatile.  This isn't as ridiculous as it sounds, since x is inherently involved in a race.  You can't safely replace the access to x by arbitrary read-only data accesses anyway, since you may, in general, read inconsistent values, and your code has to be very carefully written to avoid crashes as a result.  Even if x is an int which is guaranteed to be read in one piece, reading it twice may yield a later, followed by an earlier value.

I believe a very delicate and brittle alternative may be to replace the trailing get() in the reader with a getAndAdd(0).  This relies on data race semantics, and we don't really know what those are.  And it will break with a data race detector, which wwe should probably all be using much more regularly.  But if the code inside the read-only critical section is written very carefully, and if the implementation is more-or-less consistent with the original intent of the Java memory model, I believe it should work.

Hans



More information about the Concurrency-interest mailing list