VR-Engage  2.2
Loading...
Searching...
No Matches
vreThreadPool.h
Go to the documentation of this file.
1/*******************************************************************************
2** Copyright (c) 2025 MAK Technologies
3** All rights reserved.
4*******************************************************************************/
5
6#pragma once
7
8#include "vreUtil/export.h"
9
10#include <functional>
11#include <thread>
12#include <atomic>
13#include <vector>
14#include <memory>
15#include <future>
16#include <mutex>
17#include <queue>
18#include <chrono>
19
20namespace makVre
21{
22//! \brief A thread pool class for managing and executing asynchronous tasks
23//!
24//! This class provides a pool of worker threads that can execute jobs
25//! asynchronously. It manages thread creation, job submission, and
26//! thread synchronization. Jobs can be submitted as functions with or
27//! without arguments, and the results can be retrieved using futures.
29{
30public:
31 //! \brief Function type for jobs to be executed by the thread pool
32 using JobType = std::function<void()>;
33
34public:
35 //! \brief Constructor that initializes the thread pool with a specified number of threads
36 //!
37 //! \param threads The number of worker threads to create in the pool
38 explicit DtVreThreadPool(std::size_t threads);
39
40 //! \brief Destructor that shuts down the thread pool
41 //!
42 //! Calls shutdown(true) to ensure all threads are properly joined
44
45 //! \brief Copy constructor (deleted)
47
48 //! \brief Move constructor (deleted)
50
51 //! \brief Copy assignment operator (deleted)
53
54 //! \brief Move assignment operator (deleted)
56
57 //! \brief Shuts down the thread pool
58 //!
59 //! Stops all worker threads and optionally waits for them to complete
60 //! their current tasks.
61 //!
62 //! \param join If true, waits for all threads to finish; if false, detaches them
63 void shutdown(bool join = true);
64
65 //! \brief Returns the number of threads in the pool
66 //!
67 //! \return The total number of threads managed by this pool
68 std::size_t threadCount() const;
69
70 //! \brief Resizes the thread pool to a new number of threads
71 //!
72 //! Shuts down the current pool and creates a new one with the specified number of threads
73 //!
74 //! \param nThreads The new number of threads to use
75 void resize(std::size_t nThreads);
76
77 //! \brief Returns the number of currently active (working) threads
78 //!
79 //! \return The number of threads currently executing jobs
80 std::size_t activeCount() const;
81
82 //! \brief Submits a job with arguments to the thread pool
83 //!
84 //! \param f The function to execute
85 //! \param args The arguments to pass to the function
86 //! \return A future that can be used to retrieve the result of the function
87 template <typename F, typename... Args, typename R = typename std::result_of<F(Args...)>::type>
88 std::future<R> submitJob(F&& f, Args&&... args);
89
90 //! \brief Submits a job without arguments to the thread pool
91 //!
92 //! \param f The function to execute
93 //! \return A future that can be used to retrieve the result of the function
94 template <typename F, typename R = typename std::result_of<F()>::type>
95 std::future<R> submitJob(F&& f);
96
97 //! \brief Checks if a future is ready (completed)
98 //!
99 //! \param f The future to check
100 //! \return true if the future is ready, false otherwise
101 template <typename R>
102 static bool isFutureReady(std::future<R> const& f);
103
104 //! \brief Gets the status of a future
105 //!
106 //! \param f The future to check
107 //! \return The status of the future (ready, timeout, or deferred)
108 template <typename R>
109 static std::future_status getFutureStatus(std::future<R> const& f);
110
111 //! \brief Checks if a shared future is ready (completed)
112 //!
113 //! \param f The shared future to check
114 //! \return true if the shared future is ready, false otherwise
115 template <typename R>
116 static bool isSharedFutureReady(std::shared_future<R> const& f);
117
118 //! \brief Gets the status of a shared future
119 //!
120 //! \param f The shared future to check
121 //! \return The status of the shared future (ready, timeout, or deferred)
122 template <typename R>
123 static std::future_status getSharedFutureStatus(std::shared_future<R> const& f);
124
125protected:
126 //! \brief Gets the next job from the queue
127 //!
128 //! Waits until a job is available or the thread pool is stopped
129 //!
130 //! \return The next job to execute, or an empty function if the pool is stopped
132
133 //! \brief Empties the job queue
134 //!
135 //! Removes all pending jobs from the queue
137
138 //! \brief Creates worker threads for the pool
139 //!
140 //! \param nThreads The number of threads to create
141 void createThreads(std::size_t nThreads);
142
143protected:
144 //! \brief Collection of worker threads
145 std::vector<std::unique_ptr<std::thread>> myThreads;
146
147 //! \brief Queue of pending jobs
148 std::queue<JobType> myJobQueue;
149
150 //! \brief Flag indicating if the thread pool should stop
151 std::atomic<bool> myStop;
152
153 //! \brief Counter for the number of active threads
154 std::atomic<std::size_t> myActiveThreads;
155
156 //! \brief Mutex for synchronizing access to the job queue
157 std::mutex myMutex;
158
159 //! \brief Condition variable for notifying threads of new jobs
160 std::condition_variable myNotifier;
161};
162
163
164template <typename F, typename R>
165std::future<R> DtVreThreadPool::submitJob(F&& f)
166{
167 auto job = std::make_shared<std::packaged_task<R()>>(std::forward<F>(f));
168
169 {
170 std::unique_lock<std::mutex> lock(myMutex);
171 myJobQueue.emplace(
172 [job]()
173 {
174 (*job)();
175 });
176 }
177
178 myNotifier.notify_one();
179
180 return job->get_future();
181}
182
183template <typename F, typename... Args, typename R>
184std::future<R> DtVreThreadPool::submitJob(F&& f, Args&&... args)
185{
186 auto job = std::make_shared<std::packaged_task<R()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
187
188 {
189 std::unique_lock<std::mutex> lock(myMutex);
190 myJobQueue.emplace(
191 [job]()
192 {
193 (*job)();
194 });
195 }
196
197 myNotifier.notify_one();
198
199 return job->get_future();
200}
201
202template <typename R>
203bool DtVreThreadPool::isFutureReady(std::future<R> const& f)
204{
205 return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
206}
207
208template <typename R>
209std::future_status DtVreThreadPool::getFutureStatus(std::future<R> const& f)
210{
211 return f.wait_for(std::chrono::seconds(0));
212}
213
214template <typename R>
215bool DtVreThreadPool::isSharedFutureReady(std::shared_future<R> const& f)
216{
217 return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
218}
219
220template <typename R>
221std::future_status DtVreThreadPool::getSharedFutureStatus(std::shared_future<R> const& f)
222{
223 return f.wait_for(std::chrono::seconds(0));
224}
225} // namespace makVre
static std::future_status getSharedFutureStatus(std::shared_future< R > const &f)
Gets the status of a shared future.
Definition vreThreadPool.h:221
DtVreThreadPool(std::size_t threads)
Constructor that initializes the thread pool with a specified number of threads.
JobType getNextJob()
Gets the next job from the queue.
void resize(std::size_t nThreads)
Resizes the thread pool to a new number of threads.
static bool isFutureReady(std::future< R > const &f)
Checks if a future is ready (completed)
Definition vreThreadPool.h:203
std::vector< std::unique_ptr< std::thread > > myThreads
Collection of worker threads.
Definition vreThreadPool.h:145
std::function< void()> JobType
Function type for jobs to be executed by the thread pool.
Definition vreThreadPool.h:32
std::atomic< bool > myStop
Flag indicating if the thread pool should stop.
Definition vreThreadPool.h:151
DtVreThreadPool(const DtVreThreadPool &)=delete
Copy constructor (deleted)
DtVreThreadPool(DtVreThreadPool &&)=delete
Move constructor (deleted)
DtVreThreadPool & operator=(const DtVreThreadPool &)=delete
Copy assignment operator (deleted)
std::size_t threadCount() const
Returns the number of threads in the pool.
std::queue< JobType > myJobQueue
Queue of pending jobs.
Definition vreThreadPool.h:148
std::condition_variable myNotifier
Condition variable for notifying threads of new jobs.
Definition vreThreadPool.h:160
void shutdown(bool join=true)
Shuts down the thread pool.
void createThreads(std::size_t nThreads)
Creates worker threads for the pool.
~DtVreThreadPool()
Destructor that shuts down the thread pool.
static std::future_status getFutureStatus(std::future< R > const &f)
Gets the status of a future.
Definition vreThreadPool.h:209
std::size_t activeCount() const
Returns the number of currently active (working) threads.
DtVreThreadPool & operator=(DtVreThreadPool &&)=delete
Move assignment operator (deleted)
void emptyQueue()
Empties the job queue.
std::atomic< std::size_t > myActiveThreads
Counter for the number of active threads.
Definition vreThreadPool.h:154
static bool isSharedFutureReady(std::shared_future< R > const &f)
Checks if a shared future is ready (completed)
Definition vreThreadPool.h:215
std::future< R > submitJob(F &&f, Args &&... args)
Submits a job with arguments to the thread pool.
Definition vreThreadPool.h:184
std::mutex myMutex
Mutex for synchronizing access to the job queue.
Definition vreThreadPool.h:157
Defines export macros for the VREngage Utility library.
#define UTIL_DLL
Export/import macro for non-Windows platforms.
Definition export.h:39
Include export definitions for this library.
Definition glsVreMessageUtil.h:49