Fixposition SDK 0.0.0-heads/main-0-g7b59b93
Collection of c++ libraries and apps for use with Fixposition products
Loading...
Searching...
No Matches
thread.hpp
Go to the documentation of this file.
1/**
2 * \verbatim
3 * ___ ___
4 * \ \ / /
5 * \ \/ / Copyright (c) Fixposition AG (www.fixposition.com) and contributors
6 * / /\ \ License: see the LICENSE file
7 * /__/ \__\
8 * \endverbatim
9 *
10 * @file
11 * @brief Fixposition SDK: Thread helpers
12 *
13 * @page FPSDK_COMMON_THREAD Thread helpers
14 *
15 * **API**: fpsdk_common/thread.hpp and fpsdk::common::thread
16 *
17 */
18#ifndef __FPSDK_COMMON_THREAD_HPP__
19#define __FPSDK_COMMON_THREAD_HPP__
20
21/* LIBC/STL */
22#include <atomic>
23#include <condition_variable>
24#include <cstdint>
25#include <functional>
26#include <memory>
27#include <mutex>
28#include <string>
29#include <thread>
30
31/* EXTERNAL */
32
33/* PACKAGE */
34
35namespace fpsdk {
36namespace common {
37/**
38 * @brief Thread helpers
39 */
40namespace thread {
41/* ****************************************************************************************************************** */
42
43/**
44 * @brief A binary semaphore, useful for thread synchronisation
45 *
46 * The default state is "taken", that is, WaitFor() and WaitUntil() block (sleep) until the semaphore is "given" using
47 * Notify(). See the example in the Thread class documentation below.
48 */
50{
51 public:
53
54 /**
55 * @brief Notify ("signal", "give")
56 */
57 void Notify();
58
59 /**
60 * @brief Wait (take), with timeout
61 *
62 * @param[in] millis Number of [ms] to sleep, must be > 0
63 *
64 * @returns true if taken (within time limit), false if the timeout has expired
65 */
66 bool WaitFor(const uint32_t millis);
67
68 /**
69 * @brief Wait (take), with timout aligned to a period
70 *
71 * This blocks (sleeps) until the start of the next millis period is reached (or the semaphore has been taken). The
72 * period is aligned to the system clock. For example, with a period of 500ms it would timeout at t+0.0s, t+0.5s,
73 * t+1.0s, t+1.5s, etc. If the calculated wait duration is less then the given minimal wait duration, it waits
74 * longer than one period in order to achieve the minimal wait duration and still timeout on the start of a period.
75 *
76 * Note that this works on the actual system clock. In ROS replay scenario this may not behave as expected as the
77 * fake ROS system clock may be faster or slower than the actual system clock.
78 *
79 * @param[in] period Period duration [ms], must be > 0
80 * @param[in] min_sleep Minimal sleep duration [ms], must be < period
81 *
82 * @returns true if taken (within time limit), false if the timeout has expired or period was 0
83 */
84 bool WaitUntil(const uint32_t period, const uint32_t min_sleep = 0);
85
86 private:
87 std::mutex mutex_; //!< Mutex
88 std::condition_variable cond_; //!< Condition
89};
90
91// ---------------------------------------------------------------------------------------------------------------------
92
93/**
94 * @brief Helper class for handling threads
95 *
96 * Example:
97 *
98 * @code{.cpp}
99 * class Example {
100 * public:
101 *
102 * Example() :
103 * thread_ { "worker", std::bind(&Example::Worker, this, std::placeholders::_1) }
104 * { }
105 *
106 * void Run() {
107 *
108 * if (!thread_.Start()) {
109 * throw "...";
110 * }
111 *
112 * int n = 0;
113 * while (thread_.IsRunning()) {
114 *
115 * sleep(500);
116 * thread_.Wakeup() // = BinarySemaphore::Notify()
117 *
118 * sleep(2000);
119 * thread_.Wakeup() // = BinarySemaphore::Notify()
120 *
121 * n++;
122 * if (n >= 10) {
123 * thread_.Stop();
124 * }
125 * }
126 * }
127 *
128 * private:
129 *
130 * void Worker(void *) {
131 * while (!thread_.ShouldAbort()) {
132 * if (thread_.Sleep(1000)) { // = BinarySemaphore::SleepFor(1000)
133 * // We have been woken up
134 * } else {
135 * // Timeout expired
136 * }
137 * }
138 * }
139 *
140 * Thread thread_;
141 * };
142 * @endcode
143 */
145{
146 public:
147 using ThreadFunc = std::function<void(Thread*, void*)>; //!< Thread main function
148 using PrepFunc = std::function<void(void*)>; //!< Thread prepare function
149 using CleanFunc = std::function<void(void*)>; //!< Thread cleanup function
150
151 /**
152 * @brief Constructor
153 *
154 * @param[in] name Name of the thread, for debugging
155 * @param[in] func The thread function
156 * @param[in] arg Optional thread function user argument
157 * @param[in] prep Optional prepare function, called before the thread function
158 * @param[in] clean Optional cleanup function, called after the threadd stopped (or crashed)
159 *
160 * @note Constructing an instance delibarately does not automatically start the thread!
161 */
162 Thread(const std::string& name, ThreadFunc func, void* arg = nullptr, PrepFunc prep = nullptr,
163 CleanFunc clean = nullptr);
164
165 /**
166 * @brief Destructor, blocks until thread has stopped
167 */
169
170 // ----- Common methods -----
171
172 /**
173 * @brief Get thread name
174 * @returns the thread name
175 */
176 const std::string& GetName();
177
178 // -----------------------------------------------------------------------------------------------------------------
179
180 //! \name Main (controlling) thread methods
181 //@{
182
183 /**
184 * @brief Start the thread
185 *
186 * @note This method is used by the main, controlling thread
187 */
188 bool Start();
189
190 /**
191 * @brief Stop the thread
192 *
193 * @note This method is used by the main, controlling thread
194 */
195 void Stop();
196
197 /**
198 * @brief Wakup a sleeping thread
199 *
200 * @note This method is used by the main, controlling thread
201 */
202 void Wakeup();
203
204 /**
205 * @brief Check if thread is running
206 * @returns true if thread is running, false if it has stopped
207 * @note This method is used by the main, controlling thread
208 */
209 bool IsRunning();
210
211 //@}
212
213 // -----------------------------------------------------------------------------------------------------------------
214
215 //! \name Worker thread methods
216 //@{
217
218 /**
219 * @brief Sleep until timeout or woken up
220 *
221 * @param[in] millis Number of [ms] to sleep
222 *
223 * @returns true if the thread has been woken up, false if the timeout has expired
224 *
225 * @note This method is used by the worker thread
226 */
227 bool Sleep(const uint32_t millis);
228
229 /**
230 * @brief Sleep until next period start or woken up
231 *
232 * See BinarySemaphore::WaitUntil() for a detailed explanation.
233 *
234 * @param[in] period Period duration [ms], must be > 0
235 * @param[in] min_sleep Minimal sleep duration [ms], must be < period
236 *
237 * @returns true if the thread has been woken up, false if the timeout has expired or period was 0
238 *
239 * @note This method is used by the worker thread
240 */
241 bool SleepUntil(const uint32_t period, const uint32_t min_sleep = 0);
242
243 /**
244 * @brief Check if we should abort
245 *
246 * @note This method is used by the worker thread, typically as the predicate in the main loop, e.g.
247 * `while (!thread_.ShouldAbort()) { do_stuff(); }`
248 */
250
251 //@}
252
253 // -----------------------------------------------------------------------------------------------------------------
254
255 private:
256 // clang-format off
257 std::string name_; //!< Thread name
258 std::unique_ptr<std::thread> thread_; //!< Thread handle
259 ThreadFunc func_; //!< Thread function
260 void *arg_; //!< Thread function argument
261 PrepFunc prep_; //!< Thread prepare function
262 CleanFunc clean_; //!< Thread cleanup function
263 std::atomic<bool> abort_; //!< Abort signal
264 bool running_; //!< Running flag
265 BinarySemaphore sem_; //!< Semaphore
266 // clang-format on
267 void _Thread(); //!< Wrapper function to call the user thread function
268};
269
270// ---------------------------------------------------------------------------------------------------------------------
271
272/**
273 * @brief Set thread name
274 *
275 * Sets the thread name, which shows in htop etc.
276 *
277 * @param[in] name The thread name (1-6 characters, longer \c name is clipped at 6 chars)
278 */
279void SetThreadName(const std::string& name);
280
281/**
282 * @brief Get numeric thread ID
283 *
284 * Like std::this_thread::get_id(), but numeric (and therefore printf()-able, etc.).
285 */
286std::size_t ThisThreadId();
287
288/* ****************************************************************************************************************** */
289} // namespace thread
290} // namespace common
291} // namespace fpsdk
292#endif // __FPSDK_COMMON_THREAD_HPP__
A binary semaphore, useful for thread synchronisation.
Definition thread.hpp:50
bool WaitUntil(const uint32_t period, const uint32_t min_sleep=0)
Wait (take), with timout aligned to a period.
bool WaitFor(const uint32_t millis)
Wait (take), with timeout.
void Notify()
Notify ("signal", "give")
Helper class for handling threads.
Definition thread.hpp:145
Thread(const std::string &name, ThreadFunc func, void *arg=nullptr, PrepFunc prep=nullptr, CleanFunc clean=nullptr)
Constructor.
void Stop()
Stop the thread.
std::function< void(void *)> PrepFunc
Thread prepare function.
Definition thread.hpp:148
bool ShouldAbort()
Check if we should abort.
void Wakeup()
Wakup a sleeping thread.
std::function< void(void *)> CleanFunc
Thread cleanup function.
Definition thread.hpp:149
bool SleepUntil(const uint32_t period, const uint32_t min_sleep=0)
Sleep until next period start or woken up.
std::function< void(Thread *, void *)> ThreadFunc
Thread main function.
Definition thread.hpp:147
bool Sleep(const uint32_t millis)
Sleep until timeout or woken up.
bool IsRunning()
Check if thread is running.
bool Start()
Start the thread.
~Thread()
Destructor, blocks until thread has stopped.
const std::string & GetName()
Get thread name.
void SetThreadName(const std::string &name)
Set thread name.
std::size_t ThisThreadId()
Get numeric thread ID.
Fixposition SDK.
Definition fpsdk_doc.hpp:20