Problem statement
Applications need a way to run work concurrently without creating a thread per operation or hiding overload in an unbounded queue. This pool makes capacity, rejection, result delivery, and shutdown explicit.
Architecture
A mutex-protected FIFO feeds a fixed set of workers. Tasks execute outside the queue lock and publish results or exceptions through futures. Condition-variable predicates control sleeping and draining; a separate lock serializes external shutdown callers.
What works
- Positive configurable worker count and finite queue capacity.
- Future-returning submission, including move-only callables and arguments.
- Named full-queue and stopped-pool errors; submission never silently drops work.
- User exceptions delivered through futures without losing a worker.
- Graceful drain-and-join, repeated/concurrent external shutdown, and explicit rejection of a worker attempting to join its own pool.
- Runnable example, CMake/CTest build, and serial-versus-pool benchmark.
Testing
Tests exercise bounded admission, result delivery, task exceptions, concurrent producers, shutdown races, and destructor draining. A standalone example shows futures and move-only arguments. The repository includes CMake/CTest commands, stress-test instructions, and detailed test records.
Benchmarks
The benchmark compares serial execution with 1, 2, and 4 workers across two task sizes. Each configuration has a warmup and seven measured batches. Results include wall time, throughput, task start-delay percentiles, checksums, and environment/source metadata.
Small tasks can be slower through the pool. The benchmark documentation includes raw results, machine details, and methodology rather than a blanket performance claim.
Execution model
Queue capacity limits waiting task count, not captured bytes or active workers. Running tasks cannot be forcibly cancelled. Tasks that never finish can block shutdown; nested waits in an exhausted pool can deadlock.
I use a fixed worker set, a synchronized FIFO, and drain-and-join shutdown. References passed to tasks must remain alive, and the pool cannot be destroyed from inside its own worker.
Source and usage
Browse cpp-thread-pool on GitHub for the implementation, build instructions, runnable example, and benchmarks.
The bounded queue article explains related principles; its teaching snippet is not a substitute for this project’s codebase.