Back to Home

Producer-Consumer Queue

Watch producers fill a bounded buffer while consumers drain it

📦 What is the Producer-Consumer Pattern?

A classic concurrency pattern where one or more producers create items and place them in a shared bounded buffer, while consumers remove and process them. The buffer acts as a decoupling mechanism.

✓ Benefits

  • • Decouples production from consumption
  • • Handles speed mismatches gracefully
  • • Bounded buffer prevents memory overflow
  • • Enables parallel processing pipelines

⚠️ Blocking Behavior

  • • Full queue → producers block
  • • Empty queue → consumers block
  • • Prevents busy-waiting
  • • Uses condition variables internally

🎬 What to Watch

Watch producers turn yellow (blocked) when the queue is full, and consumers block when empty. The bounded buffer maintains backpressure!

Produced
0
Consumed
0
In Queue
0/5
Throughput
0%

Data Flow

Producers
Producer 1
idle
Producer 2
idle
Bounded Buffer (5 slots)
FrontBack
Consumers
Consumer 1
idle
Consumer 2
idle

⚡ Key Concepts

Producer Blocking

When the queue is FULL, producers must wait (block) until a consumer removes an item. This prevents memory overflow.

Consumer Blocking

When the queue is EMPTY, consumers must wait (block) until a producer adds an item. This prevents busy-waiting.

Event Log

Start simulation to see events...

Real-World Uses

  • Message queues (RabbitMQ, Kafka)
  • Job processing (Bull, Sidekiq)
  • HTTP request handling
  • Print spoolers
  • Video encoding pipelines

Implementation

// Bounded buffer with blocking
class BoundedQueue<T> {
  private queue: T[] = [];
  private maxSize: number;

  async put(item: T) {
    while (queue.length >= maxSize) {
      await this.waitForSpace();
    }
    this.queue.push(item);
    this.notifyConsumers();
  }

  async take(): Promise<T> {
    while (queue.length === 0) {
      await this.waitForItem();
    }
    const item = this.queue.shift()!;
    this.notifyProducers();
    return item;
  }
}