BCS401 Operating System Semester IV · AY 2025-26 onward
Unit 2 · Concurrent Processes

Lecture 8: Classical problems: Producer–Consumer

Learning outcomes

  • Solve the producer–consumer problem using appropriate synchronisation tools.
Lecture Notes

Main content

Classical Synchronization Problem: Producer–Consumer

The Producer–Consumer problem is one of the most important classical synchronization problems in operating systems. It models a situation where one or more producer processes generate data items and place them into a shared buffer, while one or more consumer processes remove those items and use them. The challenge is to ensure correct coordination when both producers and consumers access the same shared buffer concurrently.

Synchronization Producer–Consumer Bounded Buffer Semaphores Mutex Critical Section

1. Problem Statement

Suppose there is a finite buffer of size N. A producer inserts items into the buffer, and a consumer removes items from it. Since the buffer is shared, simultaneous access must be controlled.

A correct solution must satisfy the following:

  • A producer must not add an item when the buffer is full.
  • A consumer must not remove an item when the buffer is empty.
  • Only one process at a time should modify the shared buffer structure.
  • No data item should be lost, duplicated, or corrupted.
Main issue: The producer and consumer must synchronize their actions while sharing a common buffer safely.

2. What This Problem Models

The producer–consumer problem appears in many real systems:

  • Keyboard input placed into a buffer and read by an application
  • Print jobs produced by users and consumed by a printer service
  • Network packets produced by hardware and consumed by software
  • Streaming systems where one component generates data and another processes it

This problem is also known as the bounded-buffer problem when the shared buffer has limited capacity.

3. Why Synchronization Is Needed

If synchronization is not used, the system may suffer from:

  • Race conditions – producer and consumer update shared indices incorrectly
  • Buffer overflow – producer inserts into a full buffer
  • Buffer underflow – consumer removes from an empty buffer
  • Data inconsistency – items may be overwritten or skipped
Without synchronization: the shared buffer turns from a useful queue into a chaos machine.

4. Buffer Model

A common implementation uses a circular buffer:

  • in points to the next free position for insertion
  • out points to the next occupied position for removal
  • buffer size is fixed at N
Circular Buffer 0 1 2 3 4 5 6 out in
Figure 1: A shared circular buffer used by producers and consumers.

5. Synchronization Tools Used

A standard semaphore-based solution uses three synchronization variables:

Semaphore / Variable Meaning
mutex Ensures mutual exclusion while accessing the buffer
empty Counts how many empty slots remain in the buffer
full Counts how many filled slots are present in the buffer

Initial values for a buffer of size N are:

mutex = 1
empty = N
full = 0

6. Semaphore-Based Solution

6.1 Producer Code

do {
    item = produce_item();

    wait(empty);   // wait if buffer is full
    wait(mutex);   // enter critical section

    insert_item(item);

    signal(mutex); // leave critical section
    signal(full);  // one more filled slot
} while(true);

6.2 Consumer Code

do {
    wait(full);    // wait if buffer is empty
    wait(mutex);   // enter critical section

    item = remove_item();

    signal(mutex); // leave critical section
    signal(empty); // one more empty slot

    consume_item(item);
} while(true);

6.3 Explanation of the logic

  1. Producer first checks whether an empty slot exists using wait(empty).
  2. If the buffer is full, the producer must block.
  3. If space exists, it uses wait(mutex) to enter the critical section safely.
  4. After insertion, it leaves the critical section using signal(mutex).
  5. Then it signals full to indicate that one more item is available.
  1. Consumer first checks whether any item exists using wait(full).
  2. If the buffer is empty, the consumer must block.
  3. If an item is available, it enters the critical section using wait(mutex).
  4. After removing the item, it signals mutex and then empty.
Why this works: empty prevents overflow, full prevents underflow, and mutex prevents simultaneous modification of the shared buffer.

7. Flow of Operation

Producer wait(empty) wait(mutex) Insert Item signal(full) signal(mutex) Consumer wait(full)
Figure 2: Basic synchronization flow in the producer–consumer solution.

8. Why This Solution Is Correct

Requirement How it is satisfied
No simultaneous buffer corruption mutex ensures only one process enters the critical section at a time
No producer overflow empty blocks producer when no free slot exists
No consumer underflow full blocks consumer when no item exists
Proper synchronization Semaphore counts reflect actual buffer state

9. Bounded Buffer vs Unbounded Buffer

Case Meaning Effect on synchronization
Bounded Buffer Buffer has limited size Producer may need to wait if buffer is full
Unbounded Buffer Buffer is assumed large enough to never fill Producer never waits for space, but consumer still waits for items

In practice, most real systems use bounded buffers because memory is limited.

10. Alternative Synchronization Tools

Although semaphores are the classical solution, the producer–consumer problem can also be solved using:

  • Monitors with condition variables
  • Mutex locks with condition wait/signal operations
  • Message passing where the queue is managed by the OS or runtime
Modern view: High-level languages and libraries often hide the semaphore details, but the underlying synchronization logic is still the same.

11. Simple Worked Example

Example

Suppose buffer size = 3. Initially:

empty = 3, full = 0, mutex = 1

If the producer inserts one item:

  • wait(empty) → empty becomes 2
  • wait(mutex) → mutex becomes 0
  • item inserted
  • signal(mutex) → mutex becomes 1
  • signal(full) → full becomes 1

Now the consumer can remove the item:

  • wait(full) → full becomes 0
  • wait(mutex) → mutex becomes 0
  • item removed
  • signal(mutex) → mutex becomes 1
  • signal(empty) → empty becomes 3

So the shared buffer state remains correct throughout.

12. Common Errors in Wrong Solutions

  • Using only mutex but not tracking full/empty slots
  • Allowing producer to write without checking free space
  • Allowing consumer to read without checking item availability
  • Updating buffer pointers outside the critical section
  • Using busy waiting instead of proper blocking synchronization
Exam tip: Do not just write “use semaphores.” Show clearly what each semaphore represents and why the order of wait and signal matters.

13. Final Comparison Snapshot

Element Role in producer–consumer solution
Producer Generates and inserts items
Consumer Removes and uses items
Shared buffer Temporary storage between producer and consumer
mutex Protects the critical section
empty Counts available empty slots
full Counts available filled slots

14. One-Page Summary

The Producer–Consumer problem models the synchronization of processes sharing a common buffer. Producers insert items and consumers remove them.

A correct solution must prevent: buffer overflow, buffer underflow, and race conditions.

The standard semaphore solution uses: mutex for mutual exclusion, empty to count free slots, and full to count occupied slots.

This is one of the most important classical synchronization problems because it captures real operating-system situations involving shared queues, bounded resources, and coordinated process behavior.

One-Page Summary

15. Likely University Questions

  1. What is the producer–consumer problem? Why is synchronization needed?
  2. Explain the bounded-buffer problem with a suitable diagram.
  3. Solve the producer–consumer problem using semaphores.
  4. What are the roles of mutex, empty, and full semaphores?
  5. Differentiate between bounded buffer and unbounded buffer.
  6. What problems occur if producer–consumer synchronization is not handled properly?
  7. Can the producer–consumer problem be solved using monitors? Explain briefly.