[concurrency-interest] Extended access methods for Atomics (and AQS)

Gregg Wonderly gergg at cox.net
Mon Apr 19 16:39:13 EDT 2010


Hans, from my perspective, as just a developer that tires of having to deal with 
hardware issues, is that we shouldn't keep trying to make software easier to get 
wrong.

Multi-threading in Java, due to weak visibility guarentees, is painful. 
Further, I find it really hard to teach people this stuff, and I am not sure why 
we find it so easy to keep adding to what needs to be learned.

What I thinking about, is the fact that I see the read vs write accesses as a 
range of possibilities.  If you order them from weaker on the outside to 
stronger on the inside as something like

	non-volatile -> relaxed -> volatile:read

and

	write:volatile <- relaxed <- non-volatile

then you can imagine a "window" where particular guarantees can hold.  Outside 
of that window, things are weaker.  For any particular application, I am 
thinking that this window is never completely open.

Writes that are relaxed might be the weakest you want, while reads might even be 
non-volatile, but I'm not sure why you would make wide use of AtomicX in that case.

I am thinking then, that a set of classes with names like:

NonVolatileReadRelaxedWriteAtomicInt
RelaxedReadVolatileWriteAtomicInt

etc would be helpful in that they could have all of the methods that AtomicInt 
has, and as subclasses, they could override methods that are weaker than the 
class name stipulates and make them live up to the "name".

This would allow some interesting "plugability" for quick testing of 
visibility/synchronization as a "fix" for something.  You could plug in
VolatileReadVolatileWriteAtomicInt and see if that fixes the problem or at least 
changes the behavior in a way that suggests what the issue might be.

I still worry the most about people using weaker access by habit and then 
threading changing so that a different thread carries out a task then was used 
before and now the weaker access is not appropriate.  Those kinds of problems 
are very difficult to find, and tooling or API support to find and debug these 
types of things seems like an upfront need.

Gregg Wonderly

Boehm, Hans wrote:
> I'm not sure I fully understand this proposal.  However, I think it's important to 
> structure the interface so that, if you really need to use accessors with weaker
> ordering, you can mix them with more strongly ordered ones, including volatile
> style accesses.  For example, the second load in double-checked locking doesn't
 > actually race with anything.  Thus it's unusually safe to use a "relaxed" (or
> even "nonVolatile") access here.  But that doesn't mean you want "relaxed" 
> accesses everywhere.
> 
> I think it's also very reasonable to write code initially to use only volatile-style (sequentially consistent)accesses, and then relax that only in performance critical cases that you've hopefully spent a lot of time thinking about.
> 
> Hans
> 
>> -----Original Message-----
>> From: concurrency-interest-bounces at cs.oswego.edu 
>> [mailto:concurrency-interest-bounces at cs.oswego.edu] On Behalf 
>> Of Gregg Wonderly
>> Sent: Friday, April 16, 2010 10:30 AM
>> To: dholmes at ieee.org
>> Cc: Doug Lea; concurrency-interest at cs.oswego.edu
>> Subject: Re: [concurrency-interest] Extended access methods 
>> for Atomics (and AQS)
>>
>> I sent this earlier and apparently only replied to David...  
>> I changed some wording to try and be clearer.
>>
>> I agree with David, that the use of names which include the 
>> keywords that developers are already learning the meaning/use 
>> of would be helpful.  I also concur that in many cases, there 
>> may be bugs created by misuse just for the sake of speed, or 
>> because they are copying code from somewhere else and using 
>> it incorrectly.
>>
>> I'd think that a subclass, which completely encompasses the 
>> "asIfFinal" or "nonVolatile" etc aspects of use would be an 
>> improvement because it would provide a place for "reading 
>> javadoc" about why you might choose to use the class.  The 
>> subclass could also guarantee that the "visible" behavior was 
>> no "better" than the class was documented to provide.  I say 
>> "better" in the sense that putting these methods in 
>> AtomicInteger, for example, means that all the "set" and 
>> "get" functions are available.  I'd guess that you would not 
>> want results from the other methods that would produce 
>> differing or dissimilar behavior.
>>
>> It seems that's where the bugs would start to appear because 
>> one branch of existing code is using appropriate methods 
>> correctly and some new code is not, and occasionally 
>> visibility if fixed by one branch, while the other 
>> occasionally misses a value because of a data race for example.
>>
>> I'm wondering if subclass names which have to do with 
>> specific use cases such as 
>> "AtomicIntWithReadAsIfFinalAndWriteAsIfVolatile" etc. are useful?
>>
>> Gregg Wonderly
>>
>> David Holmes wrote:
>>  > Hi Doug,
>>  >
>>  > I think "InStoreorder" and "InRelaxedOrder" could easily 
>> be misunderstood as  > relating to "total store ordering", or 
>> "relaxed memory models" or any  > particular architecural 
>> memory model that uses that kind of terminology.
>>  >
>>  > If "InStoreOrder" means "with memory effects equivalent to 
>> setting a final  > variable" then lets just say that:
>>  >
>>  >    setAsIfFinal(int newVal)
>>  >
>>  > and similarly:
>>  >
>>  >    setAsNonVolatile(int newVal)
>>  >
>>  >
>>  > I guess this is somewhat better than Fences in that the 
>> semantics of the  > methods are easier to understand. But 
>> these are still methods that the vast  > majority of 
>> programmers won't know when it is valid to use them. They 
>> will  > only discover that they seem faster and so use them 
>> regardless :( Can we not  > "hide" them a bit better eg:
>>  >
>>  >   class DontUseMeUnlessYouKnowWhatYouAreDoingAtomicInteger extends
>>  > AtomicInteger {
>>  >       public void setAsNonVolatile(int newVal) { ... }
>>  >       ...
>>  >   }
>>  >
>>  > or a utility class
>>  >
>>  >   class DontUseMeUnlessYouKnowWhatYouAreDoingAtomicHelper {
>>  >      static void setAsNonVolatile(AtomicInteger x, int 
>> newVal) { ... }
>>  >      ...
>>  >   }
>>  >
>>  >> One further accommodation is that the encapsulated int  
>>>> state value inside AbstractQueuedSynchronizer should also  
>>>> support at least the setInStoreOrder method  >  > I fear 
>> the chance of misuse greatly outweighs any performance benefit.
>>  >
>>  >
>>  > Aside: if I ever see a bug report involving these new 
>> methods my response  > will be to request the submitter to 
>> rewrite their program using the "proper"
>>  > methods. Without tools or formalisms to establish 
>> correctness of use these  > methods will in many cases just 
>> be bugs waiting to happen.
>>  >
>>  > Cheers,
>>  > David
>>  >
>>  >
>>  >> -----Original Message-----
>>  >> From: concurrency-interest-bounces at cs.oswego.edu
>>  >> [mailto:concurrency-interest-bounces at cs.oswego.edu]On 
>> Behalf Of Doug Lea  >> Sent: Wednesday, 14 April 2010 10:53 
>> PM  >> To: concurrency-interest at cs.oswego.edu
>>  >> Subject: [concurrency-interest] Extended access methods 
>> for Atomics (and  >> AQS)  >>  >>  >> Last fall, we tabled 
>> discussion of the proposed Fences API.
>>  >> But regardless of the outcome of and future discussions 
>> when  >> we re-raise it, there seemed to be consensus that at 
>> the very  >> least, we should extend the methods of Atomic 
>> classes to support  >> the various memory effect modes that 
>> you otherwise would need  >> Fences methods to obtain.
>>  >>
>>  >> I'm finally trying this out. A draft update of 
>> AtomicInteger  >> with these changes is at:
>>  >> http://gee.cs.oswego.edu/dl/jsr166/dist/docs/java/util/concurrent/
>>  >> atomic/AtomicInteger.html
>>  >> (For now, only class AtomicInteger). Ignoring the 
>> arithmetic methods  >> (getAndAdd etc), the API looks like 
>> (with "*" in front of  >> the added methods)  >>  >> 
>> "volatile-write" mode
>>  >>     void set(int v)
>>  >>     boolean compareAndSet(int e, int v);
>>  >>     int setAndGet(int v);
>>  >>
>>  >> store-ordered (aka release, pseudo-final-field) mode  >> 
>> *  void setInStoreOrder(int v);  >> *  boolean 
>> compareAndSetInStoreOrder(int e, int v);
>>  >>     void lazySet(int v) // synonym for setInStoreOrder
>>  >>
>>  >> load-ordered (aka volatile-read, acquire) mode
>>  >>     int get();
>>  >> *  compareAndSetAndGet(int e, int v);  >>  >> 
>> relaxed-order (aka non-volatile) mode  >> *  int 
>> getInRelaxedOrder();  >> *  void setInRelaxedOrder(int v);
>>  >>     boolean weakCompareAndSet(int e, int v);
>>  >>
>>  >> Comments and suggestions about method names and  >> 
>> semantics would be very welcome. (Notice that  >> the naming 
>> scheme denigrates "lazySet", a name  >> that no one likes!)  
>>>>  >> The form of these methods is roughly similar to  >> 
>> C++0x modes (at least the ones supportable in Java),  >> but 
>> avoids the sometimes-controversial terms  >> "acquire" and 
>> "release" in mode/method names.
>>  >>
>>  >> For now, the specs are just done informally. Assuming we  
>>>> go ahead with this, we'd adapt the more formal versions 
>> done  >> in Fences drafts and place them in j.u.c.atomic 
>> package docs  >> to spell out better.
>>  >>
>>  >> Versions for other stand-alone Atomic objects 
>> (AtomicLong,  >> AtomicReference) would be equally 
>> straightforward. As always, the  >> main problems lie in the 
>> FieldUpdater forms, which are sadly  >> also the most useful. 
>> The dynamic type checking overhead  >> required for these 
>> forms is often more expensive than  >> any savings you get 
>> from weaker access modes. (This is  >> why Fences versions 
>> continue to be attractive.) However,  >> for uniformity, 
>> extended methods in these would also be  >> supported. 
>> Similarly for the Atomic*Array classes.
>>  >> And it is still conceivable that new JVM mechanics being 
>> put  >> into place for JSR292 might be used to reduce overhead.
>>  >>
>>  >> One further accommodation is that the encapsulated int  
>>>> state value inside AbstractQueuedSynchronizer should also  
>>>> support at least the setInStoreOrder method (none of  >> 
>> the other new methods seem to ever apply). Similarly  >> for 
>> AbstractQueuedLongSynchronizer. Using this as  >> appropriate 
>> speeds up ReentrantLock by 5% - 20%, so  >> is a good idea 
>> regardless of all other changes.
>>  >>
>>  >> -Doug
>>  >>
>>  >> _______________________________________________
>>  >> Concurrency-interest mailing list
>>  >> Concurrency-interest at cs.oswego.edu
>>  >> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>  >
>>  > _______________________________________________
>>  > Concurrency-interest mailing list
>>  > Concurrency-interest at cs.oswego.edu
>>  > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>  >
>>  >
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> 



More information about the Concurrency-interest mailing list