Condition variables and monitors for Delphi

If you are a .NET, Java or Delphi developer, please take a look at our advanced logging tool SmartInspect.

A condition variable is a threading abstraction which can help in implementing robust multi-threaded code. Condition variables are core features of Java (Object.wait, .notify, .notifyAll) and .NET (Monitor.Wait, .Pulse and .PulseAll) but we needed an implementation for Delphi. I couldn’t find one so we wrote my own. If you are interested in (using) the code, we made it publicly available on the following page:

Win32 Condition Variables and Monitors for Delphi

Comments are welcome.

This entry was posted in Delphi, Development. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

8 Comments

  1. JustSomeDane
    Posted August 20, 2007 at 2:38 pm | Permalink

    Coincidentally (I presume), Per Brinch Hansen, the inventor of the monitor concept, died less than a week before your release.

  2. Ivan Levashew
    Posted September 22, 2008 at 7:17 am | Permalink

    Thanks, guys. After two years of multithread development with c+pthreads and then Ada I have found Delphi’s parallel features to be, less to say, toys. I can hardly use events as freely as I was using condvars. It’s a pity that I can’t do current development in Ada: our systems are heavily tied on ADO.

  3. Ivan Levashew
    Posted September 23, 2008 at 4:36 am | Permalink

    I’ve noticed one mistake pinning out of ThreadDemo.dpr source code:

    finally
    FLock.Leave;
    end;
    FEmpty.PulseAll;

    and the same in the Put():

    finally
    FLock.Leave;
    end;
    FFull.PulseAll;

    Don’t do like this! From what I know about pthreads, it is a bounded error. One must signal on condvar only when mutex is owned.
    E. g. “FEmpty.PulseAll;” must be placed before finally. I just hope there are no bounded errors in the Threads.pas itself.

  4. Posted September 23, 2008 at 8:04 am | Permalink

    Hello Ivan,

    If I recall correctly, both variants are correct (putting the PulseAll in or after the try/finally block) for the Threads.pas implementation. PulseAll doesn’t use the external lock for synchronization, so it shouldn’t matter which variant you choose. Threads.pas is basically a port of pthreads for win32 which doesn’t require this either (also see ftp://sourceware.org/pub/pthreads-win32/sources/pthreads-w32-2-8-0-release/pthread_cond_signal.c), so it should be safe.

  5. Ivan Levashew
    Posted September 24, 2008 at 12:43 pm | Permalink

    Producer might Pulse condvar when consumer has owned mutex but is not waiting on condvar yet. Consumer will have to wait the whole timeout or infinitelly.

    Timeout in ThreadsDemo is 250 so it won’t cause serious problems in this particular case.

  6. Ivan Levashew
    Posted September 26, 2008 at 12:21 pm | Permalink

    I’ve found a discussion on this topic:

    http://thread.gmane.org/gmane.os.ecos.general/13018

  7. Posted September 26, 2008 at 12:29 pm | Permalink

    Thanks the link Ivan, I will look into it. As far as I understand it, the PulseAll is not required to be inside the lock (according to the pthreads implementation).

  8. Posted September 27, 2008 at 10:09 pm | Permalink

    To your comment above, the producer signals the condition variable only when the related predicate/condition is already true. It actually shouldn’t matter at all (performance differences aside as mentioned by your discussion) if the signal is issued within the lock or after - except if the internal implementation requires holding the lock.

    While the producer adds an item to the queue, the whole section is locked and the client cannot enter the same lock. Once the item has been added, the mutex is unlocked and the consumer can enter the critical section. Since the condition is true, it shouldn’t matter if the producer is preempted right before signaling the condition variable because the consumer does not wait anyway.

    Being able to signal the condition variable after releasing the lock seems to be an implementation specific feature since in Java and .NET, for example, you are required to hold the lock while signaling the condition variable. The new condition variable API which ships with Windows Vista, on the other hand, supports this feature as well (See SleepConditionVariableCS and WakeConditionVariable):

    You can wake other threads using WakeConditionVariable or WakeAllConditionVariable either inside or outside the lock associated with the condition variable. It is usually better to release the lock before waking other threads to reduce the number of context switches.

    As a side note, I just learned that the new Delphi 2009 finally got support for condition variables with a new TMonitor record. Also, if you are developing against Windows Vista, it’s probably a better idea to directly use their new condition variable API.

Post a Comment

Your email is never published nor shared.