[dmd-concurrency] synchronized, shared, and regular methods inside the same class

Sean Kelly sean at invisibleduck.org
Mon Jan 4 08:31:05 PST 2010


On Jan 4, 2010, at 6:46 AM, Andrei Alexandrescu wrote:

> This may be easiest to answer for people with extensive experience with Java's threading model. Consider the following D code:
> 
> class A {
>    void foo() synchronized;
>    void bar() shared;
>    void baz();
> }
> 
> If we have an object of type A, all three methods are callable. If we have an object of type shared(A), baz() is not callable. There is a remaining problem with foo() and bar(): the first uses lock-based synchronization, the second uses a sort of free threading (e.g. lock-free) that the compiler is unable to control. It follows that calls to foo() and bar() from different threads may easily create race conditions.

I'll admit that I'm leery of having shared methods in general.  Operations occurring in order can still easily produce unexpected results when multiple threads are interleaving execution.  Consider increment, for example: if "x++" is executed as "x = x + 1" (ie. a load, add, and a store).  I know that lock-free variables are somewhat of a separate topic, but I wanted to mention this now anyway.

> I think the compiler should enforce that a class either defines synchronized methods, shared methods, but not both. So the class writer must decide upfront whether they use lock-based or lock-free threading with a given class. Does this make sense? Is it too restrictive?

See above.  This would certainly be the easiest for the compiler to verify though, since it wouldn't have to reason about the interaction between lock-free operations and synchronized operations.  But perhaps this is time for a rather large set of questions: can someone define a shared non-class variable?  If so, how would such a variable work within shared and synchronized methods in these classes?  Would shared methods only allow operations on shared variables?  Or perhaps make all operations on data inside them shared regardless of how they're labeled?

> Walter asked - what if we take this one step further and force a class to define _all_ methods either synchronized, shared, or neither? In that case the keyword could be moved to the top:
> 
> shared class A { ... all methods shared ... }
> synchronized class B { ... all methods synchronized ... }
> class C { ... shared/synchronized not allowed ... }
> 
> Has experience with Java shown that it's best to design classes for concurrency in separation from single-threaded classes?

Tricky question.  In general I'd say yes, but that it stinks to have two classes for the same thing that only differ by synchronization.  Consider a container class for example.  Standard operations (insert, remove, etc) can have a "synchronized" label slapped on them and work perfectly, but iterators are a different story entirely.

> Effective Java doesn't mention that. But then there are all these methods synchronizedCollection, synchronizedList etc. that wrap the corresponding collections (which probably don't have synchronized methods). I'm reading this up, but if there's someone on this list who could save us all some time, please chime in.

With D's metaprogramming capabilities, this is a reasonable option in some cases.  Though see my comment about iterators above (foreach is obviously fine though).


More information about the dmd-concurrency mailing list