Ginger 1.1.5; VERSION ${PROJECT_VERSION}
Loading...
Searching...
No Matches
thread_pool.hpp
Go to the documentation of this file.
1#pragma once
2
23#include <condition_variable>
24#include <functional>
25#include <future>
26#include <memory>
27#include <mutex>
28#include <queue>
29#include <thread>
30#include <type_traits>
31#include <utility>
32
33namespace ginger {
34
36 public:
42 explicit thread_pool(size_t num_threads = std::thread::hardware_concurrency())
43 : stop_(false) {
44 if (num_threads == 0) {
45 num_threads = 1;
46 }
47 workers_.reserve(num_threads);
48 for (size_t i = 0; i < num_threads; ++i) {
49 workers_.emplace_back([this] { worker_loop(); });
50 }
51 }
52
54 {
55 std::lock_guard<std::mutex> lock(queue_mutex_);
56 stop_ = true;
57 }
58 condition_.notify_all();
59 for (auto& w : workers_) {
60 if (w.joinable()) {
61 w.join();
62 }
63 }
64 }
65
66 thread_pool(const thread_pool&) = delete;
68
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>>;
79
80 auto packaged
81 = std::make_shared<std::packaged_task<return_type()>>(std::forward<F>(task));
82
83 auto future = packaged->get_future();
84 {
85 std::lock_guard<std::mutex> lock(queue_mutex_);
86 if (stop_) {
87 throw std::runtime_error("enqueue on stopped thread_pool");
88 }
89 tasks_.emplace([packaged]() { (*packaged)(); });
90 }
91 condition_.notify_one();
92 return future;
93 }
94
95 private:
96 void worker_loop() {
97 while (true) {
98 std::function<void()> task;
99 {
100 std::unique_lock<std::mutex> lock(queue_mutex_);
101 condition_.wait(lock, [this] { return stop_ || !tasks_.empty(); });
102 if (stop_ && tasks_.empty()) {
103 return;
104 }
105 task = std::move(tasks_.front());
106 tasks_.pop();
107 }
108 task();
109 }
110 }
111
112 std::vector<std::thread> workers_;
113 std::queue<std::function<void()>> tasks_;
114 std::mutex queue_mutex_;
115 std::condition_variable condition_;
116 bool stop_;
117 };
118
127 inline auto get_thread_pool() -> thread_pool& {
128 static thread_pool pool(std::thread::hardware_concurrency());
129 return pool;
130 }
131
132} // namespace ginger
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
Definition logger.hpp:10
auto get_thread_pool() -> thread_pool &
Convenience accessor returning a singleton thread pool.
Definition thread_pool.hpp:127