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

Regan Heath regan at netmail.co.nz
Thu May 31 02:36:16 PDT 2012


On Wed, 30 May 2012 19:29:39 +0100, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:
> On 5/30/12 10:40 AM, Regan Heath wrote:
>> On Wed, 30 May 2012 18:16:38 +0100, Andrei Alexandrescu
>> <SeeWebsiteForEmail at erdani.org> wrote:
>>> On 5/30/12 9:43 AM, Regan Heath wrote:
>>>> On Wed, 30 May 2012 17:00:43 +0100, Andrei Alexandrescu
>>>> <SeeWebsiteForEmail at erdani.org> wrote:
>>>>
>>>>> On 5/30/12 5:32 AM, Regan Heath wrote:
>>>>>> On Wed, 30 May 2012 10:21:00 +0100, deadalnix <deadalnix at gmail.com>
>>>>>> wrote:
>>>>>>> You don't want to synchronize on ANY object. You want to  
>>>>>>> synchronize
>>>>>>> on explicit mutexes.
>>>>>>
>>>>>> +1 .. this is the key point/issue.
>>>>>
>>>>> TDPL's design only allows for entire synchronized classes (not
>>>>> separate synchronized and unsynchronized methods), which pair mutexes
>>>>> with the data they protect. This is more restrictive than exposing
>>>>> mutexes, but in a good way. We use such a library artifact in C++ at
>>>>> Facebook all the time, to great success.
>>>>
>>>> Can you call pass them to a synchronized statement? i.e.
>>>>
>>>> TDPLStyleSynchClass a = new TDPLStyleSynchClass();
>>>> synchronized(a) {
>>>> }
>>>
>>> Yes. Well I recommend acquiring the text! :o)
>>>
>>>> ... because, if you can, then you're exposing the mutex.
>>>
>>> No.
>>
>> For the purposes of this thread, and the anti-pattern/problem we're
>> discussing, you are.
>
> No. I explained in my previous post that the synchronized statement does  
> not expose locks. This is not a matter of opinion.

Well, it seems some people disagree here.  You are exposing the ability to  
lock and unlock them, which is the cause of more frequent deadlocks (this  
assertion comes from the M$ article, my experience with them and it seems  
 from other peoples experience of them as well).  You're not exposing the  
mutex primitive in any other way, but that's irrelevant for this  
discussion.  Now, you and I have probably done enough multi-threaded  
programming with mutexes that we no longer fall into this trap easily, but  
someone just starting in the world of threading/locking is going to,  
repeatedly.  If we make it impossible to do it "by default", so they have  
to think about when/where to apply the mutex, and make the code doing the  
locking more obvious, then I think we'd go a long way to making it much  
nicer.

>> It is the combination of synchronized
>> classes/methods (implicit locking) and external synchronized statements
>> (explicit locking) which result in the unexpected, accidental, and hard
>> to see deadlocks we're talking about here.
>
> You can have deadlocks but with synchronized you can't leak locks or  
> doubly-unlock them. With free mutexes you have all of the above.

I'm not suggesting using free mutexes.  I'm suggesting keeping the mutex  
private inside the object.  Private in this case means cannot be locked by  
external code.  Which basically means synchronized() is a no go "by  
default".  This will avoid all the careless accidental deadlock cases  
involving synchronized w/ synchronized classes/methods and make people  
actually think about when/where to use their mutexes, instead of just  
throwing synchronized all about the place.  It is sad, because I really  
like the scopedness of synchronized but I think it encourages lazy  
programming in this case.  Note that I said "by default" above, we can  
definitely provide library interfaces, structs, classes, etc to make  
synchronized work and if we did it would become a conscious choice the  
programmer makes to use them, and that should hopefully (because I cannot  
predict the future) mean less accidental deadlocks.

>>>>> People shouldn't create designs that have synchronized classes
>>>>> referring to one another naively. Designing with mutexes (explicit or
>>>>> implicit) will always create the possibility of deadlock, so examples
>>>>> how that could happen are easy to come across.
>>>>
>>>> True. But in my Example 1
>>>
>>> Your example 1 should not compile.
>>
>> o.. k.. I expected you would get my meaning with the simplified example.
>> Here you are:
>
> [snip]
>
>> Runs and deadlocks immediately.
>
> Sure. As I said, synchronized helps with scoping the locks and unlocks,  
> but not with deadlocks. You can rewrite the example with two bare  
> mutexes just as well.

Again, I'm not suggesting using "bare" or "free" mutexes.  I'm suggesting  
keeping the mutex private, so that it cannot be locked without it being  
obvious that that's whats happening.  If it were more obvious there would  
be less chance of an accidental deadlock, and more chance people would  
actually use an idea like an "atomic lock of multiple sync primitives"  
(your synchronized with multiple mutexes and lock ordering), where  
possible.  Sadly even that idea only works when both locks are taken in  
the same method/function and only if they can and should be taken at the  
same time .. which I think is a fairly rare case.

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/


More information about the Digitalmars-d mailing list