These problems appear in almost every OS interview. Mastering them shows you understand how to apply synchronization primitives to real concurrency challenges.
1. Producer-Consumer (Bounded Buffer)
Setup: Producers add items to a fixed-size buffer. Consumers remove items. The buffer has N slots.
Constraints:
- Producer must not add to a full buffer
- Consumer must not remove from an empty buffer
- Both must not modify the buffer simultaneously
Solution (three semaphores):
| Semaphore | Initial value | Purpose |
|---|---|---|
empty | N | Counts empty slots — producer waits, consumer signals |
full | 0 | Counts filled slots — consumer waits, producer signals |
mutex | 1 | Mutual exclusion for buffer access |
Producer: Consumer:
wait(empty) wait(full)
wait(mutex) wait(mutex)
// add item to buffer // remove item from buffer
signal(mutex) signal(mutex)
signal(full) signal(empty)
2. Readers-Writers
Setup: Multiple readers can read simultaneously. Only one writer can write. While a writer writes, no readers can read.
First variant (reader-preference): Readers can keep entering as long as no writer is active. Writer starvation is possible.
Second variant (writer-preference): Once a writer is ready, no new readers can start. Readers are allowed to finish, then writer proceeds.
Key trick: A read_count variable tracks active readers, protected by its own mutex. The writer needs a different semaphore.
3. Dining Philosophers
Setup: Five philosophers, five chopsticks. Each needs both left and right chopsticks to eat.
Deadlock scenario: All five pick up left chopstick simultaneously → all wait for right forever.
Solutions:
- Allow only 4 philosophers at the table (prevents circular wait)
- Pick up both chopsticks only if both are available
- Odd philosophers pick left first, even pick right first (asymmetric)
void philosopher(int i) {
while (true) {
think();
pickup(forks[i]); // left
pickup(forks[(i+1)%5]); // right
eat();
putdown(forks[i]);
putdown(forks[(i+1)%5]);
}
}
Q: How do semaphores solve the Producer-Consumer problem?
A: Use three semaphores: empty (starts at buffer size N — producer waits on it), full (starts at 0 — consumer waits on it), and mutex (binary — protects buffer access). This ensures producers don’t overflow and consumers don’t underflow.
Q: Can multiple readers read at the same time?
A: Yes — the readers-writers solution allows concurrent readers. A read_count variable tracks active readers. Only the first reader acquires the shared lock; subsequent readers just increment the counter. The last reader releases the lock.
Q: Explain the Dining Philosophers problem.
A: Five philosophers sit around a table, each with a chopstick between them. Each needs both chopsticks to eat. The deadlock scenario: everyone grabs the left chopstick and waits for the right. Solutions involve limiting concurrent philosophers or changing the pickup order.
Q: How does the asymmetric solution work?
A: Odd-numbered philosophers pick up the left fork first, even-numbered pick up the right fork first. This breaks the circular wait condition — the last philosopher can never start the cycle.
Premium Content
Unlock Classical Synchronization Problems and all premium lessons with a subscription.
From ₹199.99/year — See plans