[concurrency-interest] Synchronization of data read by multiple threads

Jeremy Manson jmanson at cs.purdue.edu
Tue Oct 25 15:20:59 EDT 2005


Gregg Wonderly wrote:
> 
> 
> Jeremy Manson wrote:
> 

[reminder: stopped is NOT volatile]

>> It would be perfectly legal for a compiler to examine the code in 
>> Thread 1 and determine that it does not change the value of stopped.  
>> It could then decide that what you have in Thread 1 is an infinite 
>> loop, and remove the loop guard:
>>
>> Replacement Thread 1:
>> if (!stopped) {
>>   while (true) {
>>     // do stuff
>>   }
>> }
>>
>> And Thread 1 will never end, regardless of what Thread 2 does.
> 
> 
> I don't believe this is a valid optimization.  If the visibility of 
> stopped is such that it can be referenced outside of the context the 
> compiler is optimizing, then it can't possibly make this change to the 
> code.  In that code, it would be perfectly valid for someone to code
> 
> synchronized( something ) {
>     stopped = true;
> }
> 
> and that would make the "stopped" change visible to the Thread 1 
> context.  

If you want to use a variable to communicate between threads, you need 
to synchronize both sides.  You could do:

Thread 1:
while (true) {
   synchronized (something) {
      if (stopped) break;
   }
   // stuff
}

Thread 2:
synchronized (something) {
   stopped = true;
}

And that would work fine.  But if Thread 1 does not have the 
synchronization, then it is not incumbent on that thread to be able to 
tell that Thread 2's update has occurred.

If you have to rely on visibility analysis to do compiler optimizations, 
then you aren't going to be able to perform any optimizations at all. 
Or, rather, few enough that you are going to pay a substantial 
performance hit.

 > This is java and late bindings can wreak havoc on such optimizations
 > that are possible in other languages.

Late bindings have nothing to do with this; you can imagine, if you 
like, that there are no method calls inside the loop.

It is true that a compiler is unlikely to perform this transformation if 
there are unknown method calls in the loop.  On the other hand, with 
aggressive inlining, what constitutes an unknown method call may be a 
little unpredictable.

Bear in mind as well that when I say "compiler", I actually mean "JIT 
compiler".

> If Jeremy is suggesting that the compiler has done complete visibility 
> analysis and can absolutely determine that the value is not altered, 
> perhaps it might make that change.

A compiler can make that transformation.  If you want visibility outside 
the thread, then you must use synchronization or make stopped volatile.

> I'm not convinced that such an optimization strategy would be a safe 
> thing to do.  It will create such amazingly ugly bugs.  In code that has 
> failed to utilize volatile (it didn't really work before) correctly, 
> there are problems that will be very difficult to find with such changes 
> to the code.  Now that volatile does actually work, it will be very 
> unhelpful for the language to have compilers and JITs being this 
> agressive, out of the box.

What makes you think that compilers weren't doing it before?  All it is 
is loop invariant code motion.

Now that volatile does work, programmers should be using it.  Or better 
still, if they don't understand the issues well enough to use it 
safely, they should use a JSR-166 ExecutorService for this pattern.

						Jeremy


More information about the Concurrency-interest mailing list