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

Andrei Alexandrescu andrei at erdani.com
Mon Jan 4 18:52:53 PST 2010


Sean Kelly wrote:
> I'd planned to ask this a bit later in the discussion, but I've been wondering if all methods need to be labeled as shared or synchronized or if only the public (and possibly protected) ones do?  If I have:
> 
>     class A
>     {
>         void fnA() synchronized { fnB(); } // 1
>         void fnB() shared { fnC(); } // 2
>         private void fnC() {}
>     }
> 
> Since fnC() may only be accessed through A's public interface, all of which is ostensibly safe, does fnC() have to be synchronized or shared?  I can see an argument for not allowing case 2, but it does seem safe for fnC() to be called by fnA() at least.  I know D uses recursive locks so there's no functional barrier to making fnC() synchronized, but this seems like it could be horribly slow.  I suppose the compiler could elide additional lock_acquire() calls though, based on static analysis.

We've considered using protection levels for inferring thread-related 
checks. One problem is that protection is suspended within the same 
module, which blunts its strength a lot.

Speaking of lock acquisition - Walter, one thing you may want to 
consider is to not insert synchronization code inside a method. Instead, 
put it at the call site. That way you have control over and you can 
optimize around lock calls.

>> Within such a shareable object, we can use low-level stuff like mutexes, semaphores and conditions to build the desired behaviour, wrapping it up and presenting a clean interface.
> 
> Since mutexes can override a class' monitor, it already works to do this:
> 
>     class A
>     {
>         this() {
>             mut = new Mutex( this );
>             cond = new Condition( mut );
>         }
> 
>         void fnA() synchronized { // locks "mut"
>             cond.wait(); // unlocks the lock acquired when fnA() was entered and blocks, etc.
>         }
> 
>         Mutex mut; Condition cond;
>     }

I didn't know you can do that. Where is Mutex documented? Does it 
steal/replace or supplement class' built-in mutex?

> I'm hoping this library-level trick will be enough to allow most of the classic synchronization mechanisms to be used in D 2.0.
> 
>> Re synchronized containers - I don't like the idea at all. That is going down the path of having many shared objects, which is notoriously difficult to get right, especially for non-experts. IMO, shared objects should be small in number, and serve as boundaries between threads, which otherwise play in their own separate sand-pits.
> 
> A good pathological but functionally correct example is the Thread class in core.thread.  Thread instances should really be labeled as shared, but I know that when this happens the compiler will throw a fit.  The thing is, while some of the methods are already synchronized, there are quite a few which are not and don't need to be and neither do they need the variables they access to be made lock-free.  Even weirder is:

Well I think Thread is a threading primitive so we shouldn't expect to 
be implementable without some oddities.


Andrei


More information about the dmd-concurrency mailing list