DMD 1.022 and 2.005 releases - what's wrong with threading?

David Brown dlang at davidb.org
Sat Oct 6 23:48:04 PDT 2007


On Sun, Oct 07, 2007 at 08:11:30AM +0200, downs wrote:

>Sure, on it.
>This should work .. at a glance, I wasn't able to find any cases where
>it deadlocks.
>I made an unbounded buffer, because it seemed easier ^_____^

It's half the work :-)

Congratulations, though.  It certainly isn't easy to do even unbounded
buffers in std.thread.

>  private {
>    T[] buffer;
>    bool[Thread] waiting;
>    Object waiting_sync;
>  }
>  void put(T t)
>  {
>    synchronized(this) buffer~=t;
>    while (waiting.length && buffer.length)
>      synchronized(waiting_sync)
>        foreach (thr, bogus; waiting)
>          thr.resume;
>  }
>  T get()
>  {
>    synchronized(waiting_sync) waiting[Thread.getThis]=true;
>    scope(exit) synchronized(waiting_sync) waiting.remove(Thread.getThis);
>    while (true)
>    {
>      synchronized(this)
>        if (buffer.length)
>        {
>          auto res=buffer[0];
>          buffer=buffer[1..$];
>          return res;
>        }
>      Thread.getThis.pause;
>    }
>  }

Ok everyone, let that sink in a little bit.  As far as I can tell, this is
the simplest possible synchronization using the Phobos thread primitives.
It requires two critical sections (this and waiting_sync), an associative
array of Threads, a while loop on 'put', the scope(exit) with a
synchronized blockin get().  It also isn't going to be very efficient on
any underlying implementation.  Under Linux, the implementation of pause
and resume make debugging more difficult, and prevent the user from being
able to use SIGUSR1 and SIGUSR2 for their own purposes.

This is certainly not what I would hope to ever find in a normal piece of
threading code.  Let's pretend I have condition variables (.NET style), and
see what it looks like:

   void put(T t)
   {
     synchronized (this) {
       buffer ~= t;
       conditionSignal (this);
     }
   }

   void get(T t)
   {
     synchronized (this) {
       while (buffer.length == 0)
         conditionWait (this);
       auto res=buffer[0];
       buffer = buffer[1..$];
       return res;
     }
   }

where conditionSignal and conditionWait are as defined by .NET or posix
Pthreads (with the condition variable and mutex as part of each object).
This can be implemented directly on top of both Windows and Linux, meaning
it won't hurt performance.  It's a whole lot easier to use correctly, and
doesn't obscure the code quite as much.  (Yes, the conditionWait is inside
of the synchronized, it is _required_ to be there, that's why it is so much
easier to use).  In fact, if a thread was allowed to 'pause()' itself
inside of a synchronized section and that meant it would atomically release
the critical section and pause, and then regain the critical section on
resume, the Phobos version could be made much simpler.

Other implementations using semaphores aren't much more difficult.

I still would say this is too primitive for most uses, and higher level
constructs can be made.  But, only the useful primitives need to be in the
thread library itself.

David



More information about the Digitalmars-d mailing list