[dmd-concurrency] synchronized, shared, and regular methods inside the same class
Sean Kelly
sean at invisibleduck.org
Mon Jan 4 13:17:43 PST 2010
On Jan 4, 2010, at 9:00 AM, Andrei Alexandrescu wrote:
> Sean Kelly wrote:
>> 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.
>
> Shared methods are necessary for enabling lock-free structures. For example a lock-free singly-linked list (a very useful structure) would have all of its methods shared.
My mistake. I forgot that the shared label on methods is for visibility, since unlabeled methods won't be accessible from a shared reference.
> Read-modify-write operations a la x++ do not work for shared objects. I was surprised to find out just now that dmd does not enforce that so I just added http://d.puremagic.com/issues/show_bug.cgi?id=3672.
>
> The only things that work on shared objects are:
>
> * calls to synchronized or shared methods, if any;
>
> * reading if the object is word-size or less;
>
> * writing if the object is word-size or less.
Cool! It's perhaps a minor issue right now, but it would be nice if RMW operations could be performed via library functions. Hopefully all that's required is to accept a "ref shared T" and then write ASM for the machinery from there? ie. Is there any need for compiler changes to support this?
>>> 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?
>
> Absolutely. A global shared int or a global shared pointer are typical examples.
>
>> If so, how would such a variable
>> work within shared and synchronized methods in these classes?
>
> It would obey the regular shared rules. In case you're thinking about a field, shared or synchronized methods don't change the type of an object, subject to the "tail-shared" exemption that I'll discuss at a later point.
So if I have:
class A
{
void fn() shared { x = 5; }
int x;
}
Is this legal? If the type of the object doesn't change then I'd guess that I won't be allowed to access non-shared fields inside a shared function?
>> 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?
>
> If a method is shared, it must assume "this" is shared. The fact that "this" was not shared upon invoking the method is an information that's lost.
>
> By the way - you should be able to call shared methods against a non-shared object.
>
>>> 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.
>
> In the meantime, according to what I've read, that's exactly what Java containers do. Java containers stink already, are you adding some intensity to the stench?
I really don't know Java containers very well so I can't accurately quantify the stench, but it seems like a horrible duplication of code to do this, particularly in a language that doesn't have the facilities to wrap an arbitrary class automatically.
>> 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.
>
> This supports Walter's idea that at best a class is designed from the get-go to be synchronized or not. Is that correct?
Yes I think so.
>>> 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).
>
> You mean foreach defined as synchronized opApply?
Yes exactly.
More information about the dmd-concurrency
mailing list