Learning path

Full curriculum

Full curriculum

Unit content

Producer-consumer queues and bounded buffers

A producer-consumer design separates tasks that create work from tasks that process it by placing items in a shared queue.

With an unbounded queue, producers can outrun consumers indefinitely and consume increasing memory. A bounded buffer gives the queue a finite capacity and introduces backpressure.

Conceptually, a producer waits for space before enqueueing, while a consumer waits for an item before dequeueing:

producer:                     consumer:
lock                          lock
while queue is full:          while queue is empty:
    wait(not_full)                wait(not_empty)
enqueue(item)                 item = dequeue()
signal(not_empty)             signal(not_full)
unlock                        unlock

The mutex protects the queue and its predicates; the condition variables let blocked participants sleep rather than poll.

Several producers and consumers can share the same buffer. Correctness requires that every item be inserted and removed according to the intended ownership rules, while performance depends on queue contention and the relative rates of production and consumption.

Bounded buffers are a basic building block for pipelines: finite capacity prevents unlimited accumulation and propagates pressure upstream when a downstream stage cannot keep up.