← Questions

Bounded blocking queue for producer and consumer threads

0
AppleCodingLast asked Aug 2026

Implement a first-in, first-out queue with a fixed capacity that any number of producer and consumer threads share. A thread that cannot make progress must sleep, not spin. The point is the synchronisation, so build it from a mutex and condition variables (or your language's monitor), not a ready-made concurrent queue.

Interface

Unless you agree on a different interface with the interviewer, assume:

  • BlockingQueue(capacity: int) — capacity >= 1.
  • put(item) -> None — waits while the queue is full, then appends at the tail.
  • take() -> item — waits while the queue is empty, then removes and returns the head.

Example

q = BlockingQueue(2)
put("a"); put("b")
put("c")        ->  blocks: the queue is full
take()          ->  "a"   (in another thread; the blocked put now adds "c")
take()          ->  "b"
take()          ->  "c"
take()          ->  blocks until someone puts

Constraints

  • Items leave in the order they arrived.
  • Apart from waiting, put and take are O(1).

Clarifying questions

  • Is the queue bounded? On a full queue, should put block, fail or drop?
  • Are timed variants needed (offer(item, timeout), poll(timeout))?
  • Is there a shutdown path so blocked consumers can exit?
  • Which language and threading library?

What a strong answer covers

  • One lock around the buffer and its count, with a stated invariant; a ring buffer or deque.
  • Two conditions, "not full" and "not empty", and which operation signals which.
  • A while loop around every wait, and why a single if is unsafe (spurious wakeups, a competitor taking the item first).
  • Signal-one versus signal-all, and the lost-wakeup or deadlock risk of the wrong choice with a shared condition.
  • Edge cases: capacity 1, many more producers than consumers, shutdown while threads are blocked.
  • What a mutex and condition variable do underneath (atomic instructions, sleeping in the kernel).

Follow-ups

  • Add offer(item, timeout) and poll(timeout), keeping the total wait bounded across early wakeups.
  • Add close(): consumers drain what is left and then stop, producers fail fast.
  • With one shared condition and signal-one, build an interleaving where every thread ends up asleep.
  • One lock for both ends versus separate put and take locks: what does the two-lock design gain, and what keeps it correct?
Write and test your solution herePython in your browser, the question's tests level by level, every submission kept for you.Sign in to start coding