[concurrency-interest] Fwd: Synchronization blocks, locks and reorderings

Szabolcs Ferenczi szabolcs.ferenczi at gmail.com
Wed Jan 23 17:41:25 EST 2008


F.Y.I.

---------- Forwarded message ----------
From: Szabolcs Ferenczi <szabolcs.ferenczi at gmail.com>
Date: 23 Jan 2008 19:17
Subject: Re: [concurrency-interest] Synchronization blocks, locks and
reorderings
To: Unmesh joshi <unmesh_joshi at hotmail.com>

On 23/01/2008, Unmesh joshi <unmesh_joshi at hotmail.com > wrote:
> Hi,
>
> I was reading
> http://today.java.net/pub/a/today/2004/04/13/JSR133.html .
> Discussing reordering there,
>
> class Reordering {
>   int x = 0, y = 0;
>   Object l = new Object();
>
>   public void writer() {
>     x = 1;
>     synchronized (l) {
>       y = 2;
>     }
>   }
>
>   public void reader() {
>     synchronized (l) {
>       int r1 = y;
>       int r2 = x;
>     }
>   }
> }
>
> In the happens-before discussion it is stated that,
>
> "A thread calling reader() will now see the values of x and y placed there
> by the thread calling writer(). The writer() method contains four actions
-- 
> write to x, lock l, write to y, and unlock l. By the program order rule,
the
> writes to x and y happen before the unlock of l. Similarly, the reader()
> method contains four actions -- lock l, read x, read y, and unlock l, and
> again by the program order rule the reads of x and y happen after the lock
> operation. Since by the monitor rule, the unlock operation in writer()
> happens before the lock operation in reader(), we can see (by
transitivity)
> that the writes to x and y in writer() happen before the reads of x and y
in
> reader(), and therefore the correct values are visible to the thread
calling
> reader()."
>
> I am little confused here,

If I understand it correctly, the text explains this scenario:

time writer()        reader()
---- --------        --------
t1   write to x
t2   lock l
t3   write to y
t4   unlock l
t5                   lock l
t6                   read y
t7                   read x
t8                   unlock l

There is nothing special about it except for that the shared variable x is
only handled correctly because it appears just before a critical section and
the change has some latch effect. The somewhat more interesting scenario is
this:

time writer()        reader()
---- --------        --------
t1                   lock l
t2                   read y
t3   write to x
t4                   read x
t5                   unlock l
t6   lock l
t7   write to y
t8   unlock l

Now what value of x will the reader read? According to the happens-before
stuff, value 0 will be read from x despite that x has actually value 1
already.

Despite of any "happens-before" issue, this piece of code is simply not
correct from the old fashioned concurrency point of view.---It is only
correct if you move the write to x inside the critical section. Then
compilers are free to optimize as they wish.

Let me elaborate it a little bit: This class has two pieces of "local"
resource, which are the integer variables x and y. At least one of the
methods of the class contains the `synchronized' keyword, hence the class is
meant to be a shared one and its local resources are meant to be critical
resources. Hence it could be: a monitor.---No, wait a minute. It is a Java
monitor but that is not a proper one as defined by Hoare and Brinch Hansen
in the '70s. This is why it is allowed that a piece of critical resource can
appear outside of the critical section. *It is a concurrency bug designed
into the Java language.* Now, with the fancy "happens-before" rules they are
trying to fix the problem.

The referred article claims: `Many developers mistakenly assume that
synchronization is simply a shorthand for "critical section" or
"mutex".'---Well, I am one of them. At least the keyword `synchronized'
should mark a block which is a critical section and a critical section can
be built with help of mutexes too. Perhaps Java has again some
re-interpretation of the concepts, which are traditionally used in
concurrent programming. So what is expressed in the code above is that one
of the critical resource (namely variable x) is accessed outside of the
critical section. It is a typical concurrency bug leading to hazardous
behaviour.

However, with the fancy "happens-before" interpretation of Java, even the
following non-sense piece of code is "correct":

class Reordering_2 {
  int x = 0, y = 0;
  Object l = new Object();

  public void writer() {
    x = 1;
    y = 2;
    synchronized (l) {
    }
  }

  public void reader() {
    synchronized (l) {
      int r1 = y;
      int r2 = x;
    }
  }
}

Just take the following possible interleaving:

time writer()        reader()
---- --------        --------
t1   write to x
t2   write to y
t3   lock l
t4   unlock l
t5                   lock l
t6                   read y
t7                   read x
t8                   unlock l

After this interleaving the result will be r1==2, r2==1 as can be expected.
Now let us take a different interleaving:

time writer()        reader()
---- --------        --------
t1   write to x
t2                   lock l
t3   write to y
t4                   read y
t5                   read x
t6                   unlock l
t7   lock l
t8   unlock l

After this scenario, on the other hand, the result will be, I guess, r1==0,
r2==0 which is something extra ordinary. What "happened-before" defines in
Java is not what happened before.

I hope this helps.

Best Regards,
Szabolcs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: /pipermail/attachments/20080123/56ece9a6/attachment.html 


More information about the Concurrency-interest mailing list