[D-runtime] What's with core.sync.condition usage?

Sean Kelly sean at invisibleduck.org
Thu Apr 26 12:23:21 PDT 2012


On Apr 26, 2012, at 7:50 AM, Steve Schveighoffer wrote:

> A condition variable is logically attached to an arbitrary condition as defined in your code (such as, there is an element in a queue).  The proper sequence for using a condition is:
> 
> lock(mutex);
> while(logicalConditionIsFalse) cond.wait();
> // processCondition, e.g. remove element from queue
> unlock(mutex);
> 
> It doesn't work like an event in Windows, and events in windows do *not* protect external conditions, the event *is* the condition.
> 
> For mutex/conditions, only threads waiting *at the time* you signal a condition will be woken up.  So you have to have a mutex to protect the state of the condition, otherwise, you might miss the condition signal.  You also avoid needless waiting/locking.
> 
> You might build mutex/conditions into a more high-level object (such as a queue), which would hide the details, but the primitives are correct, and time-tested.
> 
> Now, I'm all for a use case of storing the mutex in the condition and having the condition "own" the mutex, but that should not be a limitation, you should be able to attach multiple conditions to the same mutex, which means none of them own it.

This is exactly right, by the way.  Windows events are difficult to use correctly/efficiently because there's no way to atomically associate state checking with wakeup events.  Condition variables themselves are simpler because all they do is communicate the wakeup event, leaving all state checking up to the user.  They work because the transition from holding a lock on the mutex to waiting on the condition is logically atomic, as is the transition from notification to re-acquiring the mutex.  The general producer/consumer model with conditions is:


void put(T val) {
    synchronized (cond.mutex) {
        queue.pushBack(val);
        cond.notify(); // atomically unlocks mutex on call, locks on return
    }
}

T get() {
    synchronized (cond.mutex) {
        while (list.isEmpty)
            cond.wait(); // atomically unlocks mutex on call, locks on return
        return queue.popFront();
    }
}


The loop is required because it's possible that a thread waiting on the condition could wake up accidentally (say from a signal), so there's no 100% guarantee that there will actually be something in the queue.  The really nice thing about conditions is that the state checking can be as complex as you want, and you can have multiple conditions for the same mutex.


More information about the D-runtime mailing list