Knowledge Guide
HomeConcurrencyConcurrency Problems

Problem 14 Advanced Synchronization in Multi-Buffered Master-Worker Thread Pools

The right primitive turns this into three lines

A master produces items and workers consume them through a bounded buffer: producers must block when it's full, consumers must block when it's empty. The clean classic uses two counting semaphoresempty (slots free, starts at capacity) and full (items ready, starts at 0) — plus a mutex to protect the buffer structure itself. The earlier version mixed prose about "condition variables" with semaphore code, left a semaphore that was never acquired, and busy-spun a worker — all symptoms of not letting one primitive own the blocking.

Producer acquires an empty slot then releases a full slot; consumer acquires a full slot then releases an empty slot; a mutex guards the buffer
Producer acquires an empty slot then releases a full slot; consumer acquires a full slot then releases an empty slot; a mutex guards the buffer

Correct Java

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

class BoundedBuffer<T> {
    private final Queue<T> buf = new ArrayDeque<>();
    private final Semaphore empty, full;
    private final ReentrantLock mutex = new ReentrantLock();
    BoundedBuffer(int capacity) { empty = new Semaphore(capacity); full = new Semaphore(0); }

    public void put(T x) throws InterruptedException {
        empty.acquire();                 // blocks if buffer full
        mutex.lock();
        try { buf.add(x); } finally { mutex.unlock(); }
        full.release();                  // one more item to consume
    }
    public T take() throws InterruptedException {
        full.acquire();                  // blocks if buffer empty
        mutex.lock();
        T x;
        try { x = buf.poll(); } finally { mutex.unlock(); }
        empty.release();                 // one more free slot
        return x;
    }
}

Acquire the counting semaphore before the mutex, never the reverse — holding the mutex while blocking on a full/empty semaphore would deadlock the whole buffer.

Correct Go — the buffer IS a channel

Go folds all three objects into one: a buffered channel already blocks the sender when full and the receiver when empty, with the synchronization built in. This is the idiomatic answer and why Go concurrency is so terse here.

buf := make(chan T, capacity)   // bounded buffer
// producer:  buf <- x          // blocks when full
// consumer:  x := <-buf        // blocks when empty
// shut down: close(buf); for x := range buf { ... }   // drains then ends

Pitfalls

Takeaways


Re-authored for correctness for this guide (the prior version had prose/code mismatch, a dead semaphore, and a busy-spin). Classic producer-consumer (Dijkstra). See also: Semaphore, Condition Variables, Mutex Lock.

🤖 Don't fully get this? Learn it with Claude

Stuck on Problem 14 Advanced Synchronization in Multi-Buffered Master-Worker Thread Pools? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🪜 Hint ladder (no spoilers)

Progressively stronger hints — you still solve it.

I'm working on the problem **Problem 14 Advanced Synchronization in Multi-Buffered Master-Worker Thread Pools** (Concurrency). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🎨 Explain the approach visually

See the technique, not just code.

Explain the optimal approach to **Problem 14 Advanced Synchronization in Multi-Buffered Master-Worker Thread Pools** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔍 Review my solution

Catch bugs, edge cases, sub-optimality.

I'll paste my solution to **Problem 14 Advanced Synchronization in Multi-Buffered Master-Worker Thread Pools**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🔁 Drill the pattern

Lock in recognition with look-alikes.

Give me 2 problems that use the SAME underlying pattern as **Problem 14 Advanced Synchronization in Multi-Buffered Master-Worker Thread Pools**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes