Piggybacking on happens-before

211 views
Skip to first unread message

tm jee

unread,
Feb 5, 2015, 3:02:01 AM2/5/15
to mechanica...@googlegroups.com
Hi guys, 


public class Piggybacking {

 
private volatile boolean flag;
 
private Item i;

 
public void doGet() {
   
boolean _flag = flag;
   
Item _i = this.i;
   
int _one = _i.one;
   
int _two = _i.two;
   
int _three = _i.three;
 
}

 
public void doSet(Item i) {
   
this.i = i;
   flag
= true;
 
}


 
public static class Item {
   
public int one, two, three;

   
public Item(int one, int two, int three) {
     
this.one = one;
     
this.two = two;
     
this.three = three;
   
}
 
}
}

afaik, if there are two threads one calling doGet() and other calling doSet(), we are still thread-safe due to piggy-backing on happens-before relationship. Is this true?

What if there are more threads hitting doGet() and doSet()? Are we still thread-safe? 

Cheers.

Jan van Oort

unread,
Feb 5, 2015, 3:04:22 AM2/5/15
to mechanical-sympathy
What result do you want to reach with doGet() ? It has return type "void" ??? 



Fortuna audaces adiuvat - hos solos ? 

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

tm jee

unread,
Feb 5, 2015, 3:08:26 AM2/5/15
to mechanica...@googlegroups.com
It doesn't matter much, it's just a sample, the idea is to determine the thread safety of _i in it.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-sympathy+unsub...@googlegroups.com.

tm jee

unread,
Feb 5, 2015, 3:09:28 AM2/5/15
to mechanica...@googlegroups.com
maybe i should have called it doSomething() instead of doGet() ... my bad.

Aleksey Shipilev

unread,
Feb 5, 2015, 3:13:35 AM2/5/15
to mechanical-sympathy
Define "thread-safety", because I don't understand what do you mean here. Should probably be:

 public void doGet() {
   if (flag) {
     Item _i = this.i;
     int _one = _i.one;
     int _two = _i.two;
     int _three = _i.three;
   }
 }

You have to make sure you've seen the updated flag. While this provides the necessary happens-before between doSet and doGet, it still does not guarantee doGet will run "after" the doSet. 

-Aleksey.

To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.

Jan van Oort

unread,
Feb 5, 2015, 3:15:56 AM2/5/15
to mechanical-sympathy
It's not thread-safe at all. Imagine one thread calling doGet() and executing the first line of doGet(), and at the same time the other thread calling doSet() and also executing the first line of that method. The Item that doGet() gets to see is wholly indeterminate, and depends only upon the relative execution speeds and call order. The flag protects you from nothing at all IMHO -- unless you use the "flag" field to perform some sort of locking. Which becomes a source of headache when one more than one thread is simultaneously executing doGet(). 

To sum it up: if you want thread safety, this is strange and definitely the wrong approach. Use a semaphore, a mutex or - computationally the most expensive, but also the most elegant - a Barrier or a RendezVous. 



Fortuna audaces adiuvat - hos solos ? 

To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.

Ladislav Thon

unread,
Feb 5, 2015, 3:29:10 AM2/5/15
to mechanica...@googlegroups.com
I think the question here is if doGet() reads the new value of flag as set by doSet(), will it also read the new value of the item? If my limited understanding is correct, then yes, it will, but I don't think this is called "thread safety".

Freddy Guime

unread,
Feb 5, 2015, 10:12:33 AM2/5/15
to mechanica...@googlegroups.com

I’m curious about this…I think because of the volatile boolean there is no L1/L2 caching of item i, thus it hits the write barrier on the set and that forces the item reference to be published to main memory (even though it itself is not volatile), for the volatile Boolean read then forces a main memory read (with the hopes of ‘piggybacking’ a main memory read of item I as well?) , and I think isn’t this also dependent on cpu architecture (were the Haskell’s volatile reads are cacheable in l1/l2 since the volatile writes are the ones who invalidate cross-cache?). Might be my misconception (Still going through my first cup of coffee). I agree it isn’t a way to force traditional thread safety, but the side-effects are interesting.

 

 

Thanks!

 

 

 

--

Freddy Guime

O. +1 (312) 605-4524 | F. +1 (312) 635-1751  

 

 

 

From: mechanica...@googlegroups.com [mailto:mechanica...@googlegroups.com] On Behalf Of Ladislav Thon
Sent: Thursday, February 5, 2015 2:29 AM
To: mechanica...@googlegroups.com
Subject: Re: Piggybacking on happens-before

 

I think the question here is if doGet() reads the new value of flag as set by doSet(), will it also read the new value of the item? If my limited understanding is correct, then yes, it will, but I don't think this is called "thread safety".

2015-02-05 9:15 GMT+01:00 Jan van Oort <exercit...@gmail.com>:

It's not thread-safe at all. Imagine one thread calling doGet() and executing the first line of doGet(), and at the same time the other thread calling doSet() and also executing the first line of that method. The Item that doGet() gets to see is wholly indeterminate, and depends only upon the relative execution speeds and call order. The flag protects you from nothing at all IMHO -- unless you use the "flag" field to perform some sort of locking. Which becomes a source of headache when one more than one thread is simultaneously executing doGet(). 

 

To sum it up: if you want thread safety, this is strange and definitely the wrong approach. Use a semaphore, a mutex or - computationally the most expensive, but also the most elegant - a Barrier or a RendezVous. 


 

Fortuna audaces adiuvat - hos solos ? 

 

On 5 February 2015 at 09:08, tm jee <tmj...@gmail.com> wrote:

It doesn't matter much, it's just a sample, the idea is to determine the thread safety of _i in it.

On Thursday, 5 February 2015 19:04:22 UTC+11, Jan van Oort wrote:

What result do you want to reach with doGet() ? It has return type "void" ??? 


 

Fortuna audaces adiuvat - hos solos ? 

 

To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mechanical-symp...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Vitaly Davidovich

unread,
Feb 5, 2015, 10:26:34 AM2/5/15
to mechanica...@googlegroups.com
There's no "thread safety", in the traditional/common meaning of the phrase, in the piggybacking example.  As Aleksey pointed out earlier, you can use the boolean flag write/read pairs to ensure that writes done before the volatile write are visible to reads done after the volatile read of the flag; as constructed, the example is sort of meaningless because there's no actual "is the data set?" communication.

And just to dispel the common myth of a "volatile write flushes to memory", there's no such thing -- the store buffer is drained to L1, and the rest is taken care of by the standard cache coherence protocol.

Martin Thompson

unread,
Feb 5, 2015, 10:28:12 AM2/5/15
to mechanica...@googlegroups.com
Hi Freddy,

I think your understanding of caches works is not current. Try this post to get some background.


On x86 the only thing you have to worry about to achieve sequential consistency is if a value is in the store buffer and future load moves ahead of the store, provided you are using write-back memory. However hardware is not what you should be worried about. The compiler will mess with your code much more in its quest to give better performance to single threads such as register caching, loop hoisting, and reordering independent instructions.

You need to consider what are your synchronising actions and ensure they are sequentially consistent by using the appropriate concurrent primitives such as volatile fields or locks. This is how you remain data race free. An easy way to think of it is, if you have unpredictable results then you have a data race.

Martin...

Freddy Guime

unread,
Feb 5, 2015, 10:34:59 AM2/5/15
to mechanica...@googlegroups.com

tm jee

unread,
Feb 8, 2015, 1:40:38 AM2/8/15
to mechanica...@googlegroups.com
Nice discussion guys. 

What about the following code. Can it be "thread-safe" if multiple thread were to execute get() and set() ? If not why?

Cheers

public class Piggybacking2 {

   
private volatile Item item;


   
public Item get() {
       
Item _item = item;
       
return _item; // could be null
    }

   
public void set(Item item) {
       
Item _item = new Item(item.one, item.two, item.three);
        item
= _item;
   
}

    public static class Item {

       
public final int one, two, three;
}







Aleksey Shipilev

unread,
Feb 8, 2015, 2:48:01 AM2/8/15
to mechanical-sympathy
Yes, although you may relax either "volatile" or "final", depending on your exact contract and/or performance requirements. In normal applications, I'd leave both to stay on a safe side. See more here:

Reply all
Reply to author
Forward
0 new messages