A small, header-only fixed-size thread pool for C++17. Submit any
callable, get back a std::future for its result. Standard library only.
tp::ThreadPool pool(4);
auto f = pool.submit([](int a, int b) { return a + b; }, 20, 22);
int sum = f.get(); // 42, computed on a worker thread
auto g = pool.submit(work, 5000); // any callable + args- Idiomatic C++ concurrency —
std::thread,std::mutex,std::condition_variable,std::future/std::packaged_task. Workers block on the condition variable when idle; no busy-waiting. - Type-safe results —
submitreturnsstd::future<R>withRdeduced viastd::invoke_result_t; exceptions thrown by a task surface through the future. - Graceful shutdown — queued tasks run to completion before workers exit; the
destructor joins every thread (RAII, no leaks).
submitafter shutdown throws. - Verified under ThreadSanitizer — the test suite builds and passes with
-fsanitize=thread, the C++ equivalent of Go's race detector.
Clean-room, original implementation of a well-known concurrency primitive.
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
./build/demoRun the tests under ThreadSanitizer (asserts no data races):
cmake -S . -B build-tsan -DTP_SANITIZE=thread
cmake --build build-tsan
ctest --test-dir build-tsan --output-on-failureThe demo fans 8 jobs (50 ms each) across 4 workers and finishes in ~100 ms instead of the ~400 ms a serial loop would take.
tp::ThreadPool pool(threads = hardware_concurrency());
std::future<R> submit(F&& f, Args&&... args); // enqueue work
void shutdown(); // drain queue, join workers (idempotent)
std::size_t size() const noexcept; // worker count
std::size_t pending(); // queued task counttests/thread_pool_test.cpp (a dependency-free harness, run via ctest) covers:
result return, argument forwarding, 1000 tasks across the pool, exception
propagation through the future, graceful-shutdown queue draining,
submit-after-shutdown rejection, and multi-thread fan-out.
MIT