Implement a Stoppable Producer–Consumer System in C++

Quick Overview

Design a stoppable C++ producer-consumer system with a bounded FIFO, nonblocking store and retrieve calls, and rate-controlled workers. Explain mutex critical sections, atomic shutdown, bounded stop latency, memory ordering, and how a single-producer single-consumer ring buffer could provide a lock-free extension.

Implement a Stoppable Producer–Consumer System in C++

Company: Chicago

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

# Implement a Stoppable Producer–Consumer System in C++ Design and explain a C++ implementation with three classes: `Storage`, `Factory`, and `Consumer`. ### Constraints & Assumptions - `Storage` is a fixed-capacity FIFO of `int` values. - `store(item)` is nonblocking: insert and return `true` unless full; if full, do nothing and return `false`. - `retrieve(result)` is nonblocking: remove the oldest item into `result` and return `true` unless empty. - One factory and one consumer run concurrently. - A positive `itemsPerSec` controls each worker's attempt rate. - The caller, not a hardcoded timer inside a worker, owns shutdown. ### Clarifying Questions to Ask - Is the required baseline mutex-based, or must a lock-free extension also be implemented? - How precise must rate scheduling be, and is occasional drift acceptable? - How quickly must shutdown respond while a worker is waiting for its next period? ### Part 1: Thread-Safe Bounded Storage Implement the semantics of `store` and `retrieve`. Explain the critical sections and why checking `empty` or `full` separately from mutation is unsafe. #### What This Part Should Cover - One lock scope around each check-and-modify operation. - Correct full and empty behavior with no blocking. - Exception-safe locking and FIFO semantics. ### Part 2: Rate-Controlled Workers and Shutdown The factory attempts values `0, 1, 2, ...`; a value rejected because storage is full is dropped and the next attempt uses the next integer. The consumer attempts one retrieval per period. Show how the test requests both workers to stop and joins their threads. #### What This Part Should Cover - Rate calculation and handling of a positive rate. - Item numbering that advances even on a failed store. - An externally controlled atomic stop flag and bounded stop latency. ### Part 3: Memory Ordering and a Lock-Free Extension Explain why a plain `bool` stop flag is invalid, when relaxed ordering is sufficient, when acquire/release would be needed, and how a fixed-size single-producer/single-consumer ring buffer could replace the mutex queue. #### What This Part Should Cover - Data-race and happens-before reasoning. - Publication of a written slot before the consumer observes a new tail. - Safe reuse of a consumed slot after the producer observes a new head. - Why this SPSC design does not automatically generalize to multiple producers or consumers. ### Solving Hints - Keep lifetime control separate from the worker loop. - A condition variable can make a timed wait interruptible even though storage operations remain nonblocking. - Identify exactly which thread writes each ring-buffer index. ### What a Strong Answer Covers - Correct baseline code structure, not only concurrency vocabulary. - Atomicity of compound queue operations and well-defined shutdown. - Clear trade-offs among mutex simplicity, contention, stop responsiveness, and lock-free complexity. - Correct memory-order reasoning without claiming that atomics alone make arbitrary structures safe. ### Follow-up Questions 1. How would you prevent long-term rate drift compared with repeated `sleep_for` calls? 2. How can shutdown interrupt a worker sleeping for a long interval? 3. What changes for multiple producers and multiple consumers? 4. Which cache-line or false-sharing concern can affect the SPSC ring buffer?

Quick Answer: Design a stoppable C++ producer-consumer system with a bounded FIFO, nonblocking store and retrieve calls, and rate-controlled workers. Explain mutex critical sections, atomic shutdown, bounded stop latency, memory ordering, and how a single-producer single-consumer ring buffer could provide a lock-free extension.

|Home/Software Engineering Fundamentals/Chicago
Chicago logo
Chicago
Apr 20, 2026, 12:00 AM
mediumSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
1
0

Implement a Stoppable Producer–Consumer System in C++

Design and explain a C++ implementation with three classes: Storage, Factory, and Consumer.

Constraints & Assumptions

  • Storage is a fixed-capacity FIFO of int values.
  • store(item) is nonblocking: insert and return true unless full; if full, do nothing and return false .
  • retrieve(result) is nonblocking: remove the oldest item into result and return true unless empty.
  • One factory and one consumer run concurrently.
  • A positive itemsPerSec controls each worker's attempt rate.
  • The caller, not a hardcoded timer inside a worker, owns shutdown.

Clarifying Questions to Ask Guidance

  • Is the required baseline mutex-based, or must a lock-free extension also be implemented?
  • How precise must rate scheduling be, and is occasional drift acceptable?
  • How quickly must shutdown respond while a worker is waiting for its next period?

Part 1: Thread-Safe Bounded Storage

Implement the semantics of store and retrieve. Explain the critical sections and why checking empty or full separately from mutation is unsafe.

What This Part Should Cover Guidance

  • One lock scope around each check-and-modify operation.
  • Correct full and empty behavior with no blocking.
  • Exception-safe locking and FIFO semantics.

Part 2: Rate-Controlled Workers and Shutdown

The factory attempts values 0, 1, 2, ...; a value rejected because storage is full is dropped and the next attempt uses the next integer. The consumer attempts one retrieval per period. Show how the test requests both workers to stop and joins their threads.

What This Part Should Cover Guidance

  • Rate calculation and handling of a positive rate.
  • Item numbering that advances even on a failed store.
  • An externally controlled atomic stop flag and bounded stop latency.

Part 3: Memory Ordering and a Lock-Free Extension

Explain why a plain bool stop flag is invalid, when relaxed ordering is sufficient, when acquire/release would be needed, and how a fixed-size single-producer/single-consumer ring buffer could replace the mutex queue.

What This Part Should Cover Guidance

  • Data-race and happens-before reasoning.
  • Publication of a written slot before the consumer observes a new tail.
  • Safe reuse of a consumed slot after the producer observes a new head.
  • Why this SPSC design does not automatically generalize to multiple producers or consumers.

Solving Hints

  • Keep lifetime control separate from the worker loop.
  • A condition variable can make a timed wait interruptible even though storage operations remain nonblocking.
  • Identify exactly which thread writes each ring-buffer index.

What a Strong Answer Covers Guidance

  • Correct baseline code structure, not only concurrency vocabulary.
  • Atomicity of compound queue operations and well-defined shutdown.
  • Clear trade-offs among mutex simplicity, contention, stop responsiveness, and lock-free complexity.
  • Correct memory-order reasoning without claiming that atomics alone make arbitrary structures safe.

Follow-up Questions Guidance

  1. How would you prevent long-term rate drift compared with repeated sleep_for calls?
  2. How can shutdown interrupt a worker sleeping for a long interval?
  3. What changes for multiple producers and multiple consumers?
  4. Which cache-line or false-sharing concern can affect the SPSC ring buffer?
Loading comments...