synchronized (this[.classinfo]) in druntime and phobos

Alex Rønne Petersen alex at lycus.org
Wed May 30 09:19:51 PDT 2012


On 30-05-2012 18:03, Regan Heath wrote:
> On Wed, 30 May 2012 16:46:54 +0100, Andrei Alexandrescu
> <SeeWebsiteForEmail at erdani.org> wrote:
>
>> On 5/30/12 2:34 AM, deadalnix wrote:
>>> Le 29/05/2012 23:33, Andrei Alexandrescu a écrit :
>>>> On 5/29/12 1:37 AM, deadalnix wrote:
>>>>> I would say that breaking things here, with the right deprecation
>>>>> process, is the way to go.
>>>>
>>>> So what should we use for mutex-based synchronization if we deprecate
>>>> synchronized classes?
>>>>
>>>> Andrei
>>>
>>> I think something similar to range design here is the way to go.
>>>
>>> It is easy to define something like
>>>
>>> template isLockable(T) {
>>> enum isLockable = isShared!T && is(typeof(T.init.lock())) &&
>>> is(typeof(T.init.release()));
>>> }
>>>
>>> And allow locking only if(isLockable!Type) .
>>>
>>> Now we can create SyncObject or any structure we want. The point is that
>>> we lock explicit stuff.
>>
>> But in this design anyone can lock such an object, which was something
>> you advocated against.
>
> I think there is some confusion here as to what the "problem" is and is
> not.
>
> The problem is /not/ that you can lock any object.
> The problem is /not/ that we have synchronized(object) {}
> The problem is /not/ that we have synchronized classes/methods.
>
> The problem /is/ that synchronized classes/methods use a mutex which is
> exposed publicly, and it the same mutex as used by synchronized(object)
> {}. This exposure/re-use makes deadlocks more likely to happen, and
> harder to spot.

Thanks. I think the discussion was getting a bit derailed, myself being 
guilty of going off on tangential issues. Yes, the issue is exactly what 
you point out here: Exposing a locking resource publicly. The issue with 
a monitor on every object can probably be solved completely separately.

>
> Removal of this "problem" will not stop deadlocks from happening as
> they're a problem multi-threaded/lock based code will always have (*).
> It will however make them far less likely to happen accidentally. It
> will make programmers think about what/where/when and how to lock things
> rather than blithely using synchronized everywhere. It will mean using
> locks is not as easy as currently, though I think we can make it fairly
> nice with good library code and/or some co-operation between the runtime
> and synchronized() statements i.e. requiring the class implement a
> common Lockable interface for example.

One gripe I have with using interfaces is speed. David Simcha showed 
that virtual mutex calls actually *do* impact speed significantly, 
particularly in the GC in his case.

As I pointed out earlier in this thread, core.sync.mutex.Mutex allows 
both composition and inheritance, and works with the synchronized 
statement. I still think it satisfies what everyone wants, given those 
two facts, and I have yet to see any counter-arguments to that (but 
would love to hear some to get a better understanding of why some people 
are against mutexes).

>
> The fact that every object can be locked, and this means they all use
> more memory is a side issue - arguably as important for some.
>
> R
>
> (*) the best you can do to "solve" the deadlock problem is to impose
> lock acquisition ordering on your code, as in all locks must be acquired
> in a defined order, and if not an assertion/error/exception is thrown.
> This requires some sort of static/singelton/overlord class which is
> aware of all mutexes and is involved in all acquisitions/releases.
>

-- 
Alex Rønne Petersen
alex at lycus.org
http://lycus.org


More information about the Digitalmars-d mailing list