Design and Implement a Worker Thread Pool with Futures and Shutdown
Company: Microsoft
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Other
Design and implement a thread pool: a fixed set of worker threads that run tasks submitted by other threads, so the application does not start a new thread for every task. Model the classes first, then implement the parts where concurrency bugs live: submitting a task, the worker loop, delivering results and errors back to the submitter, and shutting the pool down.
As in other low-level design rounds, the interviewer looks for clear class responsibilities and correct implementations of the key methods rather than every helper.
### Constraints and Clarifications
- Any thread may submit tasks at any time, including code that is itself running inside the pool.
- The submitter must be able to wait for a task's result and must see any exception the task raised.
- Shutdown must not leave worker threads running or callers waiting forever.
- You may use the language's mutexes, condition variables and threads, but not its built-in executor or thread-pool classes.
### Clarifying Questions
- Is the number of workers fixed at creation, or should it grow and shrink with load?
- Should the task queue be bounded, and what should happen to a submission when it is full?
- On shutdown, should queued tasks that have not started still run, or be cancelled?
- Do tasks need priorities, delays or repeating schedules?
### Part 1 — Model the pool
Define the public API (creating the pool, submitting work, waiting for results, shutting down) and the classes behind it: what each one owns, the state it holds, and how the pieces interact over a task's lifetime.
```hint What the submitter keeps
Think about what object the caller holds after submitting, and how it gets connected to whichever worker eventually runs the task.
```
#### What This Part Should Cover
- A clear API, including a handle the caller uses to obtain the result or error
- Responsibilities of the pool, the task queue, the workers and the result handle
- Lifecycle states of the pool and of an individual task
- Configuration: worker count, queue bound and what happens to rejected work
### Part 2 — Implement the core
Implement `submit`, the worker loop, the result handle and `shutdown`, with both a graceful variant that finishes queued work and one that cancels it. Explain which lock protects which state, and why your workers neither spin while idle nor miss a wake-up.
```hint Waking and re-checking
Ask what a worker should do when it wakes up and finds the queue still empty, and who wakes sleeping workers when the pool shuts down.
```
#### What This Part Should Cover
- Correct use of a lock and condition variable around the queue
- Running the task outside the lock, with exceptions captured into the result handle
- Shutdown with no lost wake-ups and no caller left waiting forever
- Behavior when the queue is full or the pool has already shut down
### What a Strong Answer Covers
- A clean separation between the pool, its queue, its workers and the result handles
- Thread-safe code with no busy waiting, no lost wake-ups and no lock held while a task runs
- Results, exceptions and cancellations always delivered to the submitter
- Bounded resources and a defined policy for rejected work
- Awareness of pool-specific hazards, such as tasks that wait on other tasks in the same pool
- Sizing guidance for CPU-bound versus I/O-bound work
### Follow-up Questions
- A task submits a second task to the same pool and waits for its result. When can that deadlock, and how do you prevent it?
- How would you let the pool grow up to a maximum size under load and shrink back when idle?
- How would you add delayed and repeating tasks?
- How would you choose the number of workers for CPU-bound versus I/O-bound workloads?
Overview: Low-level design and concurrency question: design and implement a fixed-size thread pool with task submission, futures that return results or errors, and graceful or cancelling shutdown. It tests lock and condition variable use, lost wake-ups, policies for rejected work, pool sizing and deadlocks between dependent tasks.
Read the full Microsoft Software Engineer interview experience this question came from