// vdm/util/thread_pool.cpp #include "vdm/util/thread_pool.hpp" namespace vdm { ThreadPool::ThreadPool(std::size_t threads) { if (threads == 0) { threads = std::thread::hardware_concurrency(); if (threads == 0) threads = 1; } workers_.reserve(threads); for (std::size_t i = 0; i < threads; ++i) workers_.emplace_back([this] { worker_loop(); }); } ThreadPool::~ThreadPool() { { std::lock_guard lk(mu_); stopping_ = true; } cv_.notify_all(); // Join here, in the destructor body, while mu_/cv_/jobs_ are still alive. Relying on // std::jthread's implicit join would run it during member destruction — after cv_ and // mu_ are already gone, which the workers are still touching. for (auto &w : workers_) w.join(); workers_.clear(); } void ThreadPool::worker_loop() { for (;;) { std::function job; { std::unique_lock lk(mu_); cv_.wait(lk, [this] { return stopping_ || !jobs_.empty(); }); if (jobs_.empty()) { // Only reached when stopping_ and nothing left to do. return; } job = std::move(jobs_.front()); jobs_.pop(); } job(); } } } // namespace vdm