[concurrency-interest] "Volatile-like" guarantees

Niko Matsakis niko at alum.mit.edu
Thu Feb 3 01:23:48 EST 2011


David Holmes wrote:
> So does this mean you are happy that Brian's explanation is correct?
>    
No, it does not really change the question that I had.  Clearly, the 
volatile read in the getter (Rv) may precede the volatile write in the 
setter (Wv), in which case there would be no happens-before 
relationship.  However, unless I am mistaken, in that case it is still 
possible that the non-volatile read (Rf) sees the write from the 
non-volatile write (Wf).  Intuitively, in some execution, the reads in 
the getter may occur in between the two writes in the setter.  In that 
scenario, the write to f occurs first, then both reads, then the 
volatile write to v.  So there is no happens-before relationship, but 
the read may see the write to f (it also may not, as there is no 
happens-before relationship to force the issue).  Now reads which follow 
the getter are not guaranteed to the see writes which preceded the setter.

The difference between this scenario and the normal volatile example is 
that the volatile write is not the "significant" write.  In other words, 
the intended usage of volatile as I understand is that one performs 
various writes W, then writes a value to the volatile field that serves 
as a signal to the reader.  The reader, seeing that value, performs 
various dependent reads that would not be safe had the writes W not been 
completed.  In this scenario, though, it is not the write to the 
volatile that signals the reader, but rather the write to the 
non-volatile field f.  The question then is can a volatile read/write be 
used purely as a supplement and, if so, what is the right way to do it.

To motivate the question, I am working on a compiler for a parallel 
language.  The language generally guarantees data-race freedom, but in 
some cases it allows the user to signal that they permit data-races; in 
those cases I would still like to guarantee sequential consistency.  The 
problem is that a single class may be used both in a racy and non-racy 
context.  The conservative thing to do then is to mark all fields 
volatile, but that penalizes the non-racy context, which is by far the 
most common.  I could generate two versions of the class, and maybe 
eventually I will, but for the moment I'd like to use a simpler scheme.  
A final option, then, is to have a delegate class which optionally uses 
a volatile field in the way that I have shown here to add in memory 
barriers.  So, in that case, writes to a field "f" would be compiled as

     this.f = ...;
     this.delegate.synchronizeWrite();

where synchronizeWrite() would either do nothing (non-ract case) or 
write a dummy value to a volatile field (racy case).  The question is, 
will a scheme like this work?  (Of course, it may also prove to be slow, 
if the cost of the method call is too high, but that could be optimized 
in various ways)



Niko


More information about the Concurrency-interest mailing list