Using of core.sync.condition.Condition

Steven Schveighoffer schveiguy at yahoo.com
Mon Oct 24 07:12:46 PDT 2011


On Fri, 21 Oct 2011 14:32:15 -0400, Alexander <aldem+dmars at nk7.net> wrote:

> Hi,
>
> I've the code (see below) which produces an exception (SyncException  
> "Unable to wait for condition")
> unless "synchronized" is used when waiting on condition (Fedora Linux,  
> 32 bit, DMD 2.055).
>
> Do I do something wrong? Using "synchronized" when accessing anything  
> that is synchronization object
> by itself is a little bit counter-intuitive, IMHO.
>
> ---snip---
> import std.conv;
> import std.stdio;
> import core.thread;
> import core.sync.mutex;
> import core.sync.condition;
>
> __gshared Mutex         mutex;
> __gshared Condition     cond;
>
> void logs(string text)
> {
>          synchronized {
>                  writeln(text);
>          }
> }
>
> void worker()
> {
>          logs("Worker started");
>          while (true) {
>                  //synchronized (mutex)
>                  {
>                          try {
>                                  cond.wait();
>                          } catch (Exception ex) {
>                                  logs("Oops: %s" ~ to!string(ex));
>                                  return;
>                          }
>                  }
>                  logs("Got notify");
>          }
> }
>
> void main()
> {
>          mutex = new Mutex();
>          cond = new Condition(mutex);
>          (new Thread(&worker)).start();
>          (new Thread(&worker)).start();
>          (new Thread(&worker)).start();
>          (new Thread(&worker)).start();
>          Thread.sleep(dur!("msecs")(250));
>          logs("Sending notify");
>          cond.notifyAll();
>          thread_joinAll();
> }
> ---snip---

When waiting on a condition, you must have its associative mutex locked,  
or Bad Things could happen.  You should also have the mutex locked when  
signaling the condition, but I don't think that's an absolute requirement.

The typical producer-consumer process works like this:

__gshared bool data;

void thread1()
{
    while(1)
    {
       synchronized(mutex)
       {
          if(!data)
          {
              data = true; // produce!
              condition.notify();
          }
       }
    }
}

void thread2()
{
    synchronized(mutex)
    {
       while(!data)
           condition.wait();
       data = false; // consume!
    }
}

The key here is, waiting on a condition atomically unlocks the mutex.  If  
waiting on a condition was allowed without locking the mutex, potentially  
thread2 could miss thread1's signal, and you encounter a deadlock!

-Steve


More information about the Digitalmars-d mailing list