Skillversitas

Condition Variables

A condition variable lets a thread sleep until another thread announces that some state has changed. It is the right tool when "proceed" depends on a predicate, not on a fixed number of permits: the consumer waits until the queue is non-empty, the worker waits until its job is marked done. In Python it is the threading.Condition class, which always wraps a lock.

wait and notify

  • wait(timeout=None) - releases the underlying lock and blocks until notified (or the timeout expires), then re-acquires the lock before returning.
  • notify(n=1) - wakes up to n waiting threads.
  • notify_all() - wakes every waiting thread.

The critical discipline: wait() must be called while holding the condition's lock, and the predicate must be re-checked in a loop after waking, because spurious wakeups and competing consumers both exist.

Producer-Consumer

import threading
import time

buf = []
cv = threading.Condition()

def producer():
    for i in range(5):
        with cv:
            buf.append(i)
            cv.notify()
        time.sleep(0.1)

def consumer():
    for _ in range(5):
        with cv:
            while not buf:               # loop: re-check the predicate
                cv.wait(timeout=5)
            item = buf.pop(0)
        print("consumed", item)

pt = threading.Thread(target=producer)
ct = threading.Thread(target=consumer)
pt.start(); ct.start()
pt.join(); ct.join()

Signaling Completion

Condition variables also implement the "wait for all workers" pattern without join(): each worker, when it finishes, increments a counter under the lock and notifies; the coordinator waits until the counter reaches the expected total:

done = 0
cv = threading.Condition()

def worker():
    global done
    do_work()
    with cv:
        done += 1
        cv.notify_all()

with cv:
    while done < 4:
        cv.wait(timeout=30)

Summary

Use Condition when a thread should block until a state predicate becomes true. Always wait in a while not predicate loop while holding the condition's lock, notify after mutating the state, and prefer notify() when only one waiter can act on the change.