23#include <condition_variable>
42 explicit thread_pool(
size_t num_threads = std::thread::hardware_concurrency())
44 if (num_threads == 0) {
47 workers_.reserve(num_threads);
48 for (
size_t i = 0; i < num_threads; ++i) {
49 workers_.emplace_back([
this] { worker_loop(); });
55 std::lock_guard<std::mutex> lock(queue_mutex_);
58 condition_.notify_all();
59 for (
auto& w : workers_) {
76 template <
typename F>
auto enqueue(F&& task)
77 -> std::future<std::invoke_result_t<std::decay_t<F>>> {
78 using return_type = std::invoke_result_t<std::decay_t<F>>;
81 = std::make_shared<std::packaged_task<return_type()>>(std::forward<F>(task));
83 auto future = packaged->get_future();
85 std::lock_guard<std::mutex> lock(queue_mutex_);
87 throw std::runtime_error(
"enqueue on stopped thread_pool");
89 tasks_.emplace([packaged]() { (*packaged)(); });
91 condition_.notify_one();
98 std::function<void()> task;
100 std::unique_lock<std::mutex> lock(queue_mutex_);
101 condition_.wait(lock, [
this] {
return stop_ || !tasks_.empty(); });
102 if (stop_ && tasks_.empty()) {
105 task = std::move(tasks_.front());
112 std::vector<std::thread> workers_;
113 std::queue<std::function<void()>> tasks_;
114 std::mutex queue_mutex_;
115 std::condition_variable condition_;
128 static thread_pool pool(std::thread::hardware_concurrency());
Definition thread_pool.hpp:35
~thread_pool()
Definition thread_pool.hpp:53
thread_pool(size_t num_threads=std::thread::hardware_concurrency())
Construct a thread pool with the given number of worker threads.
Definition thread_pool.hpp:42
thread_pool & operator=(const thread_pool &)=delete
auto enqueue(F &&task) -> std::future< std::invoke_result_t< std::decay_t< F > > >
Definition thread_pool.hpp:76
thread_pool(const thread_pool &)=delete
auto get_thread_pool() -> thread_pool &
Convenience accessor returning a singleton thread pool.
Definition thread_pool.hpp:127