FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
thread_pool.h
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2024-present FERS Contributors (see AUTHORS.md).
4//
5// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
6
7/**
8 * @file thread_pool.h
9 * @brief A simple thread pool implementation.
10 */
11
12#pragma once
13
14#include <condition_variable>
15#include <functional>
16#include <future>
17#include <mutex>
18#include <queue>
19#include <thread>
20#include <vector>
21
22namespace pool
23{
24 /**
25 * @class ThreadPool
26 * @brief A simple thread pool implementation.
27 */
29 {
30 public:
31 /**
32 * @brief Constructs a ThreadPool with a specified number of threads.
33 * @param numThreads The number of threads in the pool.
34 */
35 explicit ThreadPool(unsigned numThreads);
36
37 /**
38 * @brief Destroys the ThreadPool, joining all threads.
39 */
41
42 ThreadPool(const ThreadPool&) = delete;
43 ThreadPool& operator=(const ThreadPool&) = delete;
46
47 /**
48 * @brief Enqueues a task to be executed by the thread pool.
49 * @tparam F The type of the function to be executed.
50 * @tparam Args The types of the arguments to the function.
51 * @param f The function to be executed.
52 * @param args The arguments to the function.
53 * @return A future that will hold the result of the function.
54 * @throws std::runtime_error if the thread pool is stopped.
55 */
56 template <class F, class... Args>
57 std::future<std::invoke_result_t<F, Args...>> enqueue(F&& f, Args&&... args)
58 {
59 using ReturnType = std::invoke_result_t<F, Args...>;
60
61 auto task = std::make_shared<std::packaged_task<ReturnType()>>(
62 std::bind(std::forward<F>(f), std::forward<Args>(args)...));
63
64 std::future<ReturnType> res = task->get_future();
65 {
66 std::unique_lock lock(_queue_mutex);
67 if (_stop)
68 {
69 throw std::runtime_error("enqueue on stopped ThreadPool");
70 }
71
72 ++_pending_tasks;
73 _tasks.emplace([task] { (*task)(); });
74 _condition.notify_one();
75 }
76 return res;
77 }
78
79 /**
80 * @brief Waits for all tasks in the thread pool to finish.
81 */
82 void wait()
83 {
84 std::unique_lock lock(_queue_mutex);
85 _done_condition.wait(lock, [this] { return _pending_tasks == 0; });
86 }
87
88 /**
89 * @brief Returns the number of threads available for executing tasks.
90 * @return The number of available threads.
91 */
92 [[nodiscard]] unsigned getAvailableThreads();
93
94 private:
95 using Task = std::function<void()>;
96
97 std::vector<std::thread> _workers; ///< Vector of worker threads.
98 std::queue<Task> _tasks; ///< Queue of tasks to be executed.
99 std::mutex _queue_mutex; ///< Mutex for synchronizing access to the task queue.
100 std::condition_variable _condition; ///< Condition variable for task notification.
101 std::condition_variable _done_condition; ///< Condition variable for task completion notification.
102 std::atomic<bool> _stop = false; ///< Flag indicating whether the thread pool is stopped.
103 std::atomic<unsigned> _pending_tasks = 0; ///< Count of pending tasks.
104 };
105}
A simple thread pool implementation.
Definition thread_pool.h:29
~ThreadPool()
Destroys the ThreadPool, joining all threads.
std::future< std::invoke_result_t< F, Args... > > enqueue(F &&f, Args &&... args)
Enqueues a task to be executed by the thread pool.
Definition thread_pool.h:57
ThreadPool(const ThreadPool &)=delete
ThreadPool & operator=(const ThreadPool &)=delete
ThreadPool & operator=(ThreadPool &&)=delete
void wait()
Waits for all tasks in the thread pool to finish.
Definition thread_pool.h:82
unsigned getAvailableThreads()
Returns the number of threads available for executing tasks.
ThreadPool(ThreadPool &&)=delete