www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Using of core.sync.condition.Condition

reply Alexander <aldem+dmars nk7.net> writes:
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---

-- 
/Alexander
Oct 21 2011
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 21 Oct 2011 14:32:15 -0400, Alexander <aldem+dmars 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
Oct 24 2011
next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Oct 24, 2011, at 7:12 AM, Steven Schveighoffer wrote:
=20
 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.
=20
 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! Bartosz just posted a tutorial on Mutexes and Conditions. How timely: = http://www.corensic.com/Learn/Resources/ConcurrencyTutorialPartSeven.aspx=
Oct 24 2011
prev sibling parent Alexander <aldem+dmars nk7.net> writes:
On 24.10.2011 16:12, Steven Schveighoffer wrote:

 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!
OK, thanks. For ages I didn't touch pthreads stuff, so I forgot this semantics completely :) -- /Alexander
Oct 26 2011