21 using Task = std::packaged_task<void()>;
27 throw std::invalid_argument(
"The argument 'threadCount' has to be greate or equal to one!");
28 m_threads.reserve(threadCount);
29 for(std::size_t i = 0; i < threadCount; ++i)
30 m_threads.emplace_back([
this] { threadFunc(); });
37 for(
auto& t : m_threads)
39 if(std::this_thread::get_id() == t.get_id())
41 std::cerr <<
"ERROR in ThreadPool joins itself" << std::endl;
55 template<
typename TFnObj,
typename... TArgs>
56 auto enqueueTask(TFnObj&& task, TArgs&&... args) -> std::future<void>
58 auto ptask =
Task{[=, t = std::forward<TFnObj>(task)]() noexcept(noexcept(task(args...))) { t(args...); }};
59 auto future = ptask.get_future();
61 std::lock_guard<std::mutex> lock{m_mutex};
62 m_tasks.push(std::move(ptask));
70 while(!m_stop.load(std::memory_order_relaxed))
72 std::optional<Task> task;
74 std::lock_guard<std::mutex> lock{m_mutex};
77 task = std::move(m_tasks.front());
84 std::this_thread::yield();
88 std::vector<std::thread> m_threads;
89 std::queue<Task> m_tasks;
91 std::atomic<bool> m_stop =
false;
Defines implementation details that should not be used directly by the user.
A thread pool yielding when there is not enough work to be done.
std::packaged_task< void()> Task
ThreadPool(std::size_t threadCount)
Creates a thread pool with a given thread count.
~ThreadPool()
Destroys the thread pool, blocking until all enqueued work is done.
auto enqueueTask(TFnObj &&task, TArgs &&... args) -> std::future< void >
Runs the given function on one of the pool in First In First Out (FIFO) order.