May 30, 2012
On 5/30/12 12:26 PM, Alex Rønne Petersen wrote:
> On 30-05-2012 21:17, 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 missed that message. I don't think synchronized classes should go
>> away. I think synchronize on non synchronized classes should go away.
>
> This is something I can agree on.

Then I'm unclear what we disagree about.

Andrei

May 30, 2012
Le 30/05/2012 21:45, Andrei Alexandrescu a écrit :
> On 5/30/12 12:22 PM, deadalnix wrote:
>> Le 30/05/2012 20:03, cal a écrit :
>>> On Wednesday, 30 May 2012 at 17:46:11 UTC, Dmitry Olshansky wrote:
>>>> [snip]
>>>>>>> Such an object is known to be lockable, and most object will not
>>>>>>> be. It will avoid liquid lock, because most thing will not be
>>>>>>> lockable.
>>>>>>
>>>>>> I'm celebrating day 2 of having no idea what a liquid lock is.
>>>>>
>>>>> I have to confess to this as well. I'm starting to suspect that he
>>>>> really means deadlock. Searching on Google for "liquid lock mutex"
>>>>> literally brings up this very NG thread. :)
>>>>>
>>>> Maybe it's livelock?
>>>>
>>>> P.S. Just trying to snatched the prize in this little guess-game :)
>>>
>>> FWIW, I recently came across the term here:
>>> http://schneide.wordpress.com/tag/liquid-lock/
>>
>> I explained that in another post a few minutes ago, and yes, this is it.
>>
>> Maybe i should write an article on that, I though it was more well known.
>
> As a side note, I'm highly weary of inventing new terminology. This is a
> general remark, not related to this particular instance. Most often when
> I personally found the need to invent a new term, it was because of not
> having done my homework of looking at related work.
>
> Andrei

I didn't invented that term. But this is off topic. How would you call that phenomena ?
May 30, 2012
Le 30/05/2012 21:42, Andrei Alexandrescu a écrit :
> On 5/30/12 12:17 PM, 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 missed that message. I don't think synchronized classes should go
>> away. I think synchronize on non synchronized classes should go away.
>
> I agree.
>
> Andrei

Ha, this is getting somewhere :D
May 30, 2012
On 5/30/12 12:51 PM, deadalnix wrote:
>>>> http://schneide.wordpress.com/tag/liquid-lock/
>>>
>>> I explained that in another post a few minutes ago, and yes, this is it.
>>>
>>> Maybe i should write an article on that, I though it was more well
>>> known.
>>
>> As a side note, I'm highly weary of inventing new terminology. This is a
>> general remark, not related to this particular instance. Most often when
>> I personally found the need to invent a new term, it was because of not
>> having done my homework of looking at related work.
>>
>> Andrei
>
> I didn't invented that term. But this is off topic.

I know. Apparently Daniel Lindner invented it in a blog post that made no inroads on the net in five months.

> How would you call
> that phenomena ?

"Researching related work". It's very common outside the academic circles, and very frowned upon inside them.


Andrei
May 30, 2012
On 5/30/12 12:52 PM, deadalnix wrote:
> Le 30/05/2012 21:42, Andrei Alexandrescu a écrit :
>> On 5/30/12 12:17 PM, 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 missed that message. I don't think synchronized classes should go
>>> away. I think synchronize on non synchronized classes should go away.
>>
>> I agree.
>>
>> Andrei
>
> Ha, this is getting somewhere :D

It's getting where I was the whole time.

Andrei
May 30, 2012
On 30-05-2012 21:49, Andrei Alexandrescu wrote:
> On 5/30/12 12:26 PM, Alex Rønne Petersen wrote:
>> On 30-05-2012 21:17, 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 missed that message. I don't think synchronized classes should go
>>> away. I think synchronize on non synchronized classes should go away.
>>
>> This is something I can agree on.
>
> Then I'm unclear what we disagree about.
>
> Andrei
>

OK, so we agree that synchronizing on non-synchronized classes is a Bad Thing (TM) and should be disallowed. We also agree that (while it is a somewhat tangential issue) the extra word used in every object is wasteful (right?).

Now, it's clear that a synchronized class has to store its mutex somewhere. We could have synchronized classes add an implicit, hidden field that holds the mutex. Personally, I feel that this might add a little too much magic (and also forces using the GC), but maybe it's just me. What I pointed out earlier in this thread is that core.sync.mutex.Mutex can be used both in a compositional style and through inheritance. For example:

class MySynchronizedObject : Mutex
{
}

auto mso = new MySynchronizedObject;

synchronized (mso) // this calls lock and unlock on the mutex that mso *is* since it inherits Mutex directly, i.e. no implicit monitor is created.
{
    // ...
}

So basically, I think the question is this: Should synchronized classes implicitly have core.sync.mutex.Mutex as their base class instead of object.Object, or should they contain a hidden field? Both options involve magic, which might be undesirable. The inheritance solution obviously places restrictions on what base type can be used for synchronized classes. The hidden field solution means forcing use of the GC.

Am I making sense? Thoughts on this?

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
May 30, 2012
Le 30/05/2012 21:58, Andrei Alexandrescu a écrit :
> It's getting where I was the whole time.
>
> Andrei

So we have a communication problem.
May 30, 2012
On Wed, 30 May 2012 15:48:47 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> To clarify:
>
> On 5/30/12 12:25 PM, Alex Rønne Petersen wrote:
>>  The mutex may not be
>> directly exposed in the sense that you can obtain a reference (though in
>> reality in all compiler implementations, you can), but it is exposed in
>> the sense that you can lock and unlock it, which is a mutation of state
>> and program flow.
>
> synchronized (object) {
>      writeln("about to unlock the object");
>      XXX
>      writeln("unlocked the object");
> }
>
> Replace "XXX" with a construct that unlocks the object.

This is not what we are talking about.

I guess the easiest way to say it is, the API used to "lock and then subsequently unlock" the mutex.  That is, even this:

Object o = new Object;

synchronized(o)
{
}

is exposing the mutex in such a way that you can interfere with the semantic meaning of the mutex, and cause preventable deadlocks.

It would be preferrable for:

synchronized(o)
{
}

to be an error, unless typeof(o) allows it explicitly.

I gave you a case where you can have a deadlock, even with simple fully synchronized classes.  You might say, "yeah, but all mutexes can have deadlocks!".

My contention is that if the default is you do *not* expose the mutex to external callers, there *cannot* be a deadlock.

Here is the example again:

synchronized class A
{
  private int _foo;
  @property int foo() { return _foo;}
}

synchronized class B
{
   private A _a;
   @property A a() { return _a;}
   void fun() {}
}

void thread(B b)
{
   synchronized(b.a)
   {
      b.fun();
   }
}

If synchronized(b.a) is valid, deadlock can occur.  If it's invalid, deadlock *cannot* occur.

-Steve
May 30, 2012
Le 30/05/2012 22:31, Steven Schveighoffer a écrit :
> On Wed, 30 May 2012 15:48:47 -0400, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> To clarify:
>>
>> On 5/30/12 12:25 PM, Alex Rønne Petersen wrote:
>>> The mutex may not be
>>> directly exposed in the sense that you can obtain a reference (though in
>>> reality in all compiler implementations, you can), but it is exposed in
>>> the sense that you can lock and unlock it, which is a mutation of state
>>> and program flow.
>>
>> synchronized (object) {
>> writeln("about to unlock the object");
>> XXX
>> writeln("unlocked the object");
>> }
>>
>> Replace "XXX" with a construct that unlocks the object.
>
> This is not what we are talking about.
>
> I guess the easiest way to say it is, the API used to "lock and then
> subsequently unlock" the mutex. That is, even this:
>
> Object o = new Object;
>
> synchronized(o)
> {
> }
>
> is exposing the mutex in such a way that you can interfere with the
> semantic meaning of the mutex, and cause preventable deadlocks.
>
> It would be preferrable for:
>
> synchronized(o)
> {
> }
>
> to be an error, unless typeof(o) allows it explicitly.
>
> I gave you a case where you can have a deadlock, even with simple fully
> synchronized classes. You might say, "yeah, but all mutexes can have
> deadlocks!".
>
> My contention is that if the default is you do *not* expose the mutex to
> external callers, there *cannot* be a deadlock.
>
> Here is the example again:
>
> synchronized class A
> {
> private int _foo;
> @property int foo() { return _foo;}
> }
>
> synchronized class B
> {
> private A _a;
> @property A a() { return _a;}
> void fun() {}
> }
>
> void thread(B b)
> {
> synchronized(b.a)
> {
> b.fun();
> }
> }
>
> If synchronized(b.a) is valid, deadlock can occur. If it's invalid,
> deadlock *cannot* occur.
>
> -Steve

This cannot remove all deadlocks, but yes, it goes in the right direction.
May 30, 2012
On Wednesday, May 30, 2012 12:12:15 Andrei Alexandrescu wrote:
> On 5/30/12 12:03 PM, Steven Schveighoffer wrote:
> > On Wed, 30 May 2012 14:32:59 -0400, Andrei Alexandrescu
> > 
> > <SeeWebsiteForEmail@erdani.org> wrote:
> >> On 5/30/12 10:47 AM, Steven Schveighoffer wrote:
> >>> Yes, you can just use a private mutex. But doesn't that just lead to recommending not using a feature of the language?
> >> 
> >> I don't think so. Synchronized classes are the unit of scoped locking in D. If you want to do all scoped locking internally, make the class private.
> > 
> > Maybe you didn't read thoroughly the first part of my post (the example that shows a deadlock that is easily preventable if the mutex isn't exposed).
> 
> The mutex is not exposed.

No, you can't directly access the mutex externally, but a synchronized block used on a synchronized object uses the same mutex that the object does.

So, if you have

synchronized class C
{
}

then this synchronized block

C c;
synchronized(c)
{
}

will use the exact same mutex that any functions on C itself use. So, it's possible for code outside of your class to lock that mutex using a synchronized statement. They do _not_ have direct access to the mutex to do whatever they want with it, but they _can_ lock via synchronized statements, which means that the synchronized class does _not_ have total control over what code locks its mutex.

All that's required to fix this particular problem is to make it illegal to use a synchronized block on a synchronized object - either that or give synchronized object's two mutexes (one to use internally for its functions and one to be locked externally using synchronized blocks). The doesn't necessarily solve all of the issues being discussed here, but it _does_ solve the issue of a synchronized class not being the only entity with the ability to lock its mutex.

- Jonathan M Davis