On Wed, 30 May 2012 15:48:47 -0400, Andrei Alexandrescu <seewebsiteforem...@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

Reply via email to