Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Condition variables

A mutex stops two threads running the same code at once. A condition variable lets a thread sleep until another thread tells it something has changed, instead of checking over and over.

#cmdline "-mt"

'' A one-slot mailbox: the producer waits while it is full, the
'' consumer waits while it is empty.
type Mailbox
    as any ptr lock, changed
    as boolean full
    as int32 item
end type

sub Producer( byval p as any ptr )
    var box = cptr( Mailbox ptr, p )
    for n as int32 = 1 to 5
        mutexlock( box->lock )
        do while box->full                 '' re-test after every wake-up
            condwait( box->changed, box->lock )
        loop
        box->item = n * 10
        box->full = true
        condsignal( box->changed )
        mutexunlock( box->lock )
    next
end sub

dim box as Mailbox
box.lock = mutexcreate( )
box.changed = condcreate( )
var worker = threadcreate( @Producer, @box )

for k as int32 = 1 to 5
    mutexlock( box.lock )
    do until box.full                      '' sleeps, releasing the lock
        condwait( box.changed, box.lock )
    loop
    print "took"; box.item
    box.full = false
    condsignal( box.changed )
    mutexunlock( box.lock )
next

threadwait( worker )
conddestroy( box.changed )
mutexdestroy( box.lock )

Output

took 10
took 20
took 30
took 40
took 50

The mailbox holds one item. The producer thread waits while it is full; the main program waits while it is empty. Each side changes full with the mutex held and then calls condsignal, which wakes a thread sleeping on changed. The five items arrive in order because neither side can get ahead of the other.

condwait( cond, mutex ) does three things: it releases the mutex, sleeps until it is signalled, and takes the mutex back before it returns. Releasing the mutex is what lets the other thread change full in the meantime.

Always test the condition in a loop, as both do while box->full and do until box.full do. A wake-up says only that something may have changed: the thread can be woken with nothing to do, or find that another thread has already taken what it was woken for.

CallDoes
condcreate( ), conddestroy( c )make and free a condition variable
condwait( c, m )release m, sleep until signalled, retake m
condsignal( c )wake one thread waiting on c
condbroadcast( c )wake every thread waiting on c

A channel with a capacity of 1 does the same job as this mailbox in a few lines. Reach for a condition variable when the condition is more than "a value is waiting".

Activities

  1. Make the mailbox hold up to three items, with a count instead of full.
  2. Start two consumer threads and use condbroadcast when the producer finishes.