Producer-consumer using queue

Producer-consumer uses a shared bounded queue buffer: producers enqueue items, consumers dequeue items. Full and empty states control when each side waits.

On this page
  • Bounded buffer model
  • Queue operations in synchronization context
  • C simulation (single-threaded demo)

1) Buffer states

StateProducer actionConsumer action
EmptyCan produceMust wait
PartialCan produceCan consume
FullMust waitCan consume

2) Example in C (queue simulation)

#include <stdio.h>

#define CAP 5

int q[CAP];
int f = 0;   // front index
int r = -1;  // rear index
int sz = 0;  // current number of items in buffer

int is_full(void) {
    return sz == CAP;
}

int is_empty(void) {
    return sz == 0;
}

// Producer inserts one item into bounded circular queue
void produce(int x) {
    if (is_full()) {
        printf("Producer waits (full)\n");
        return;
    }

    r = (r + 1) % CAP;
    q[r] = x;
    sz++;
    printf("Produced %d\n", x);
}

// Consumer removes one item from bounded circular queue
void consume(void) {
    if (is_empty()) {
        printf("Consumer waits (empty)\n");
        return;
    }

    int x = q[f];
    f = (f + 1) % CAP;
    sz--;
    printf("Consumed %d\n", x);
}

int main(void) {
    // Demo event sequence (single-thread simulation)
    produce(10);
    produce(20);
    consume();
    produce(30);
    produce(40);
    produce(50);
    produce(60);
    consume();
    consume();
    consume();

    return 0;
}

Initial state

VariableValue
f (front)0
r (rear)-1
sz (size)0
Queue array[?, ?, ?, ?, ?]
CAP5

Complete execution table

StepOperationfrszQueue Array (indices 0-4)Output
0Initial0-10[?, ?, ?, ?, ?]-
1produce(10)001[10, ?, ?, ?, ?]Produced 10
2produce(20)012[10, 20, ?, ?, ?]Produced 20
3consume()111[10, 20, ?, ?, ?]Consumed 10
4produce(30)122[10, 20, 30, ?, ?]Produced 30
5produce(40)133[10, 20, 30, 40, ?]Produced 40
6produce(50)144[10, 20, 30, 40, 50]Produced 50
7produce(60)105[60, 20, 30, 40, 50]Produced 60
8consume()204[60, 20, 30, 40, 50]Consumed 20
9consume()303[60, 20, 30, 40, 50]Consumed 30
10consume()402[60, 20, 30, 40, 50]Consumed 40

Queue wrapping visualization

After Step 6 (before produce(60)):

Indices:   0     1     2     3     4
Values:  [10,   20,   30,   40,   50]
              ↑                   ↑
              f                   r

After Step 7 (produce(60) wraps to index 0):

Indices:   0     1     2     3     4
Values:  [60,   20,   30,   40,   50]
          ↑     ↑
          r     f

After final consume (step 10):

Indices:   0     1     2     3     4
Values:  [60,   20,   30,   40,   50]
                    ↑
                    f (points to next to consume)
          ↑
          r (rear points to last produced)

Final output

Produced 10
Produced 20
Consumed 10
Produced 30
Produced 40
Produced 50
Produced 60
Consumed 20
Consumed 30
Consumed 40

Key observations

AspectValue/Behavior
Queue TypeCircular buffer (array-based)
Capacity5 items maximum
Full conditionsz == CAP
Empty conditionsz == 0
Wrap-aroundWhen r = 4, next produce wraps to index 0
Producer blockingOnly prints message (simulation, not actual blocking)
Consumer blockingOnly prints message when empty
FIFO OrderMaintained even with wrap-around
Remaining itemsAfter step 10: sz=2 (items 50 and 60 remain in queue)

Note: This is a single-thread simulation of producer-consumer behavior. In a real multi-threaded environment, produce() and consume() would block/wait when full/empty instead of just printing messages.

3) Complexity

  • enqueue/dequeue: O(1)
  • buffer space: O(CAP)

Key takeaway

Producer-consumer is a queue-centered concurrency pattern. In multithreaded versions, combine this queue logic with mutex + condition variables/semaphores.