On Wed, 30 May 2012 18:16:38 +0100, Andrei Alexandrescu <seewebsiteforem...@erdani.org> wrote:
On 5/30/12 9:43 AM, Regan Heath wrote:
On Wed, 30 May 2012 17:00:43 +0100, Andrei Alexandrescu
<seewebsiteforem...@erdani.org> wrote:

On 5/30/12 5:32 AM, Regan Heath wrote:
On Wed, 30 May 2012 10:21:00 +0100, deadalnix <deadal...@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. 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.

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:

import core.thread;
import std.random;
import std.stdio;

class C
{
  synchronized void ccc() { writefln("c.ccc()"); }
}

class D
{
  synchronized void ddd() { writefln("d.ddd()"); }
}

shared C c;
shared D d;

void main()
{
  c = new shared(C)();
  d = new shared(D)();
  Thread thread1 = new Thread( &threadFunc1 );
  Thread thread2 = new Thread( &threadFunc2 );
  thread1.start();
  thread2.start();
  Thread.sleep(dur!("seconds")(60));
}

void threadFunc1()
{
  Random gen = rndGen();

  while(1)
  {
    synchronized(c)
    {
      printf("threadFunc1 sync(c) %p, obtain d.. %p\n", c, d);
      d.ddd();
    }
        
    Thread.sleep(dur!("usecs")(gen.front()));
    gen.popFront();
  }
}

void threadFunc2()
{
  Random gen = rndGen();

  while(1)
  {
    synchronized(d)
    {
      printf("threadFunc1 sync(d) %p, obtain c.. %p\n", d, c);
      c.ccc();
    }
        
    Thread.sleep(dur!("usecs")(gen.front()));
    gen.popFront();
  }
}

Runs and deadlocks immediately.

TDPL improves on deadlocks by introducing synchronized statements with
more than one argument, see 13.15.

Is there anywhere I can see this online? (for free :p)

http://goo.gl/ZhPM2

Thanks.

R

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

Reply via email to