Ocean
Loading...
Searching...
No Matches
Thread.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_BASE_THREAD_H
9#define META_OCEAN_BASE_THREAD_H
10
11#include "ocean/base/Base.h"
12#include "ocean/base/Lock.h"
14#include "ocean/base/Triple.h"
15
16#if defined(_WINDOWS)
17 #include <winsock2.h>
18 #include <windows.h>
19#else
20 #include <pthread.h>
21#endif
22
23#include <atomic>
24
25namespace Ocean
26{
27
28/**
29 * This class implements a thread.
30 * The implementation can be used in two ways:<br>
31 * First: Derive an own class from this thread class and overwrite the internal Thread::threadRun() function.<br>
32 * This function will then be called once the thread has been started. If this run function returns the thread will be closed.<br>
33 * Second: Set the run callback function which will be called instead of the normal internal run function.<br>
34 * Similar to the first solution the thread will be closed after the callback function returns.<br>
35 * However, if the normal internal run function is overloaded by a derived call a possible defined callback function has no effect.<br>
36 *
37 * Each thread can be started using the Thread::startThread() function,<br>
38 * and stopped using the Thread::stopThread() function.<br>
39 * However, the stop function will not explicit terminate the thread, it sets the thread's should-stop-state only.<br>
40 * Therefore, an implementation using this thread class must check the thread's should-stop-state recurrently.<br>
41 * Use Thread::shouldThreadStop() to determine whether your implementation should stop the thread execution.<br>
42 *
43 * If the thread execution does not return after a Thread::stopThread() the thread can be kill in an explicit manner.<br>
44 * Beware: Such kind of rough termination should be avoided and in most cases evidences a dirty usage of the internal run function.<br>
45 *
46 * See this tutorial:
47 * @code
48 * // Any class using the thread class as base class.
49 * class Timer : protected Thread
50 * {
51 * public:
52 *
53 * // Creates a new timer object.
54 * Timer();
55 *
56 * // Stars the timer.
57 * void start();
58 *
59 * // Stops the timer.
60 * void stop()
61 *
62 * private:
63 *
64 * // Internal thread run function which overloaded the function from the thread class.
65 * void threadRun() override;
66 * };
67 *
68 * Timer::Timer() :
69 * Thread("Optional thread name")
70 * {
71 * // nothing to do here
72 * // optional the thread could be started here,
73 * // however we use the start function for this explicitly
74 * }
75 *
76 * void Timer::start()
77 * {
78 * startThread();
79 * }
80 *
81 * void Timer::stop()
82 * {
83 * stopThread();
84 * }
85 *
86 * void Timer::threadRun()
87 * {
88 * // check whether this thread should stop execution
89 * while (shouldThreadStop() == false)
90 * {
91 * // do anything a timer can do
92 *
93 * // to avoid a very high CPU load it can be suitable to sleep this thread for a small time
94 * sleep(1);
95 * }
96 *
97 * // now the run function will return and the thread will be closed
98 * }
99 *
100 * // Usage of the timer in any environment, here it is used in a main function
101 * void main()
102 * {
103 * Timer timer;
104 * timer.start();
105 *
106 * // do anything in a e.g. message loop
107 *
108 * timer.stop();
109 * }
110 * @endcode
111 * @see ThreadPool, Scheduler, Worker.
112 * @ingroup base
113 */
114class OCEAN_BASE_EXPORT Thread
115{
116 public:
117
118 /**
119 * This class implements a platform independent wrapper for thread ids.
120 */
122 {
123 friend class Thread;
124
125 public:
126
127 /**
128 * Creates a new thread id object with invalid id value.
129 */
130 ThreadId() = default;
131
132 /**
133 * Returns whether this object holds a valid id.
134 * @return True, if succeeded
135 */
136 inline bool isValid() const;
137
138 /**
139 * Returns the hash value of this thread id.
140 * On platforms directly providing a unique integer thread id as value the hash value is exactly that integer value.
141 * @return The unique hash value of this thread id
142 */
143 inline uint64_t hash() const;
144
145 /**
146 * Returns whether two thread id objects are identical.
147 * @param id The second thread id to compare
148 * @return True, if succeeded
149 */
150 inline bool operator==(const ThreadId& id) const;
151
152 /**
153 * Returns whether two thread id objects are not identical.
154 * @param id The second thread id to compare
155 * @return True, if succeeded
156 */
157 inline bool operator!=(const ThreadId& id) const;
158
159 /**
160 * Compares two thread id objects by their hash values.
161 * @param id The second thread id to compare
162 * @return True, if the hash value of this object is smaller than the hash value of the second object
163 */
164 inline bool operator<(const ThreadId& id) const;
165
166 protected:
167
168 /**
169 * Creates a new thread id object.
170 * @param value The value to be wrapped by the new object
171 */
172 explicit inline ThreadId(const uint64_t value);
173
174 /**
175 * Returns an invalid thread id value.
176 * @return The invalid thread id value
177 */
178 static constexpr uint64_t invalidThreadId();
179
180 protected:
181
182 /// The value of the thread id.
183 uint64_t value_ = invalidThreadId();
184 };
185
186 /**
187 * Definition of different thread priority values.
188 */
190 {
191 /// The thread runs if the system is idle.
193 /// The thread has a priority below normal.
195 /// The thread has a normal priority.
197 /// The thread has a priority above normal.
199 /// The thread has a high priority.
201 /// The thread has a real time priority.
202 PRIORTY_REALTIME
203 };
204
205 protected:
206
207#if defined(_WINDOWS)
208#else
209
210 /**
211 * Definition of a pair holding a thread id and a boolean state.
212 */
213 typedef std::pair<pthread_t, bool> TimedJoinPair;
214
215#endif
216
217 public:
218
219 /**
220 * Creates a new thread object.
221 * The thread will be initialized with a seed value automatically generated by using RandomI::random32().
222 * @param name Optional thread name which can be helpful for debugging tasks
223 */
224 explicit Thread(const std::string& name = std::string());
225
226 /**
227 * Creates a new thread object.
228 * @param randomNumberSeedValue An explicit seed value for the random number initialization, with range [0, infinity)
229 * @param name Optional thread name which can be helpful for debugging tasks
230 */
231 explicit Thread(const unsigned int randomNumberSeedValue, const std::string& name = std::string());
232
233 /**
234 * Destructs a thread object.
235 */
236 virtual ~Thread();
237
238 /**
239 * Starts the thread.
240 * @return True, if the thread is not active
241 */
243
244 /**
245 * Informs the thread to stop.
246 * see shouldThreadStop().
247 */
249
250 /**
251 * Terminates the thread.
252 * Beware: The thread will be terminated in a very rough way.
253 * @return True, if the thread could be terminated
254 */
256
257 /**
258 * Waits until this thread has been stopped.
259 * @param timeout The number of milliseconds the caller thread will wait for this thread, -1 to wait infinite
260 * @return True, if the thread has finished; False, if the timeout was exceeded
261 */
262 bool joinThread(const unsigned int timeout = (unsigned int)(-1));
263
264 /**
265 * Returns whether this thread should stop.
266 * @return True, if so
267 * @see stopThread().
268 */
269 bool shouldThreadStop() const;
270
271 /**
272 * Returns whether this thread has been invoked to start immediately.
273 * Beware: No information is provided whether the thread is active already.
274 * However, to not start a thread invoked to start again, instead wait for the termination.
275 * @return True, if so
276 */
278
279 /**
280 * Returns whether this thread is active.
281 * An active thread currently executes the internal thread function.
282 * @return True, if so
283 */
284 bool isThreadActive() const;
285
286 /**
287 * Sleeps the calling thread for a given time.
288 * @param ms Sleeping time in ms
289 */
290 static void sleep(unsigned int ms);
291
292 /**
293 * Gives up the remaining thread time.
294 */
295 static void giveUp();
296
297 /**
298 * Returns the thread id of the current (calling) thread.
299 * @return The thread id of the current thread
300 */
302
303 /**
304 * Returns the priority of the current thread.
305 * @return Thread priority
306 */
308
309 /**
310 * Sets the priority of the current thread.
311 * @param priority Thread priority to set
312 * @return True, if succeeded
313 */
314 static bool setThreadPriority(const ThreadPriority priority);
315
316 /**
317 * Waits until an object/variable has an expected value.
318 * @param object Reference to the object/variable whose value is to be checked
319 * @param expectedValue The value that the object/variable is expected to have
320 * @param timeout The optional timeout of this function, in seconds, with range [0, infinity), -1 to wait forever
321 * @return True, if the object/variable had the expected value when this function returned; False, if a timeout was defined and the timeout exceeded
322 * @tparam TObject The data type of the object/variable to check
323 * @tparam TExpectedValue The data type of the expected value
324 */
325 template <typename TObject, typename TExpectedValue>
326 static bool waitForValue(TObject& object, const TExpectedValue& expectedValue, const double timeout = -1.0);
327
328 /**
329 * Waits until an object/variable has an expected value.
330 * The provided temporary scoped lock will be repeatingly locked and released while the function is waiting and while accessing the object/variable.<br>
331 * The temporary scoped lock needs to be locked before calling this function, and it will also be locked when the function returns.
332 * @param object Reference to the object/variable whose value is to be checked
333 * @param expectedValue The value that the object/variable is expected to have
334 * @param temporaryScopedLock The temporary scoped lock which needs to be locked when calling the function; will be locked when the function returns
335 * @param timeout The optional timeout of this function, in seconds, with range [0, infinity), -1 to wait forever
336 * @return True, if the object/variable had the expected value when this function returned; False, if a timeout was defined and the timeout exceeded
337 * @tparam TObject The data type of the object/variable to check
338 * @tparam TExpectedValue The data type of the expected value
339 */
340 template <typename TObject, typename TExpectedValue>
341 static bool waitForValue(TObject& object, const TExpectedValue& expectedValue, TemporaryScopedLock& temporaryScopedLock, const double timeout = -1.0);
342
343#ifdef __APPLE__
344
345 /**
346 * Implements a thread join function with timeout value.
347 * Depending on the platform, this function may not exist in the default libraries (e.g., on Apple platforms).
348 * @param thread The thread for which the ending function will wait
349 * @param retval The optional return value of the thread
350 * @param abstime The absolute timestamp after which the thread will have been ended
351 * @return Zero (0), if succeeded
352 */
353 static int pthread_timedjoin_np(pthread_t thread, void** retval, const struct timespec* abstime);
354
355#endif
356
357 protected:
358
359 /**
360 * Disabled copy constructor.
361 * @param thread The object that would be copied
362 */
363 Thread(const Thread& thread) = delete;
364
365 /**
366 * Creates the thread itself.
367 */
369
370 /**
371 * Destroys the thread itself.
372 * However the thread must be terminated before!
373 */
375
376 /**
377 * Tries to stop the thread gracefully.
378 * However, if the thread can not be stopped it is terminated in a rough manner.<br>
379 * Call this function in the destructor of a derived class.
380 * @param timeout Time to wait for a graceful thread termination, in ms
381 */
382 void stopThreadExplicitly(const unsigned int timeout = 5000u);
383
384 /**
385 * This function has to be overloaded in derived class.
386 */
387 virtual void threadRun() = 0;
388
389 /**
390 * The disabled assign operator.
391 * @param thread The object that would be assigned
392 */
393 Thread& operator=(const Thread& thread) = delete;
394
395 private:
396
397#ifdef __APPLE__
398
399 /**
400 * The helper function for the pthread_timedjoin_np() implementation.
401 * @param threadData The thread's data
402 * @return The return value of the thread
403 */
404 static void* pthread_timedjoin_np_helper(void* threadData);
405
406#endif
407
408 /**
409 * Platform independent internal thread function calling the external thread function.
410 */
412
413#if defined(_WINDOWS)
414
415 /**
416 * Internal thread function calling the external thread function.
417 * @param data The data object which will contain the thread owner object
418 * @return Thread return value
419 */
420 static DWORD __stdcall staticThreadRun(void* data);
421
422#else
423
424 /**
425 * Internal thread function calling the external thread function.
426 * @param data The data object which will contain the thread owner object
427 */
428 static void* staticThreadRun(void* data);
429
430#endif
431
432 private:
433
434#if defined(_WINDOWS)
435
436 /// Internal windows thread handle.
437 HANDLE threadHandle_ = nullptr;
438
439#else
440
441 /// Internal pthread object.
442 pthread_t threadObject_ = 0;
443
444#endif
445
446 /// Determines whether this thread should stop.
447 std::atomic<bool> threadShouldStop_{false};
448
449 /// Determines whether this thread is actually running.
450 bool threadIsActive_ = false;
451
452 /// Determines whether this thread has been invoked to start immediately.
453 bool threadIsInvokedToStart_ = false;
454
455 /// Name of the thread.
456 std::string threadName_;
457
458 /// The seed value for random number generators.
459 unsigned int threadRandomNumberSeedValue_ = 0u;
460};
461
462inline Thread::ThreadId::ThreadId(const uint64_t value) :
463 value_(value)
464{
465 // nothing to do here
466}
467
468inline bool Thread::ThreadId::isValid() const
469{
470 return value_ != invalidThreadId();
471}
472
473inline uint64_t Thread::ThreadId::hash() const
474{
475 return value_;
476}
477
478inline bool Thread::ThreadId::operator==(const ThreadId& id) const
479{
480 return value_ == id.value_;
481}
482
483inline bool Thread::ThreadId::operator!=(const ThreadId& id) const
484{
485 return !(*this == id);
486}
487
488inline bool Thread::ThreadId::operator<(const ThreadId& id) const
489{
490 return hash() < id.hash();
491}
492
494{
495 return uint64_t(-1);
496}
497
498template <typename TObject, typename TExpectedValue>
499bool Thread::waitForValue(TObject& object, const TExpectedValue& expectedValue, const double timeout)
500{
501 const Timestamp startTimestamp(timeout < 0.0 ? false : true);
502
503 while (true)
504 {
505 if (object == expectedValue)
506 {
507 return true;
508 }
509
510 if (timeout >= 0.0 && startTimestamp.hasTimePassed(timeout))
511 {
512 return false;
513 }
514
515 // let's sleep for 1ms
516
517 sleep(1u);
518 }
519}
520
521template <typename TObject, typename TExpectedValue>
522bool Thread::waitForValue(TObject& object, const TExpectedValue& expectedValue, TemporaryScopedLock& temporaryScopedLock, const double timeout)
523{
524 ocean_assert(!temporaryScopedLock.isReleased());
525
526 Lock* lock = temporaryScopedLock.lock();
527 ocean_assert(lock != nullptr);
528
529 if (object == expectedValue)
530 {
531 return true;
532 }
533
534 temporaryScopedLock.release();
535
536 const Timestamp startTimestamp(timeout < 0.0 ? false : true);
537
538 while (true)
539 {
540 temporaryScopedLock.relock(*lock);
541
542 if (object == expectedValue)
543 {
544 return true;
545 }
546
547 if (timeout >= 0.0 && startTimestamp.hasTimePassed(timeout))
548 {
549 return false;
550 }
551
552 temporaryScopedLock.release();
553
554 // let's sleep for 1ms
555
556 sleep(1u);
557 }
558}
559
560}
561
562#endif // META_OCEAN_BASE_THREAD_H
This class implements a recursive lock object.
Definition Lock.h:31
This class implements a recursive scoped lock object allowing to release the lock before the scoped o...
Definition Lock.h:254
void relock(Lock &lock)
Re-locks this scoped lock with a given lock.
Definition Lock.h:525
Lock * lock() const
Returns the lock object which (if existing) is locked during the existence of this scoped lock object...
Definition Lock.h:509
void release()
Explicitly releases the lock before the scoped lock object is released.
Definition Lock.h:514
bool isReleased() const
Returns whether this scoped lock is released already.
Definition Lock.h:536
This class implements a platform independent wrapper for thread ids.
Definition Thread.h:122
uint64_t hash() const
Returns the hash value of this thread id.
Definition Thread.h:473
bool isValid() const
Returns whether this object holds a valid id.
Definition Thread.h:468
ThreadId()=default
Creates a new thread id object with invalid id value.
static constexpr uint64_t invalidThreadId()
Returns an invalid thread id value.
Definition Thread.h:493
bool operator!=(const ThreadId &id) const
Returns whether two thread id objects are not identical.
Definition Thread.h:483
bool operator<(const ThreadId &id) const
Compares two thread id objects by their hash values.
Definition Thread.h:488
bool operator==(const ThreadId &id) const
Returns whether two thread id objects are identical.
Definition Thread.h:478
This class implements a thread.
Definition Thread.h:115
static ThreadId currentThreadId()
Returns the thread id of the current (calling) thread.
void createThread()
Creates the thread itself.
bool startThread()
Starts the thread.
Thread & operator=(const Thread &thread)=delete
The disabled assign operator.
static bool setThreadPriority(const ThreadPriority priority)
Sets the priority of the current thread.
bool isThreadInvokedToStart() const
Returns whether this thread has been invoked to start immediately.
void stopThread()
Informs the thread to stop.
std::string threadName_
Name of the thread.
Definition Thread.h:456
void destroyThread()
Destroys the thread itself.
bool terminateThread()
Terminates the thread.
Thread(const Thread &thread)=delete
Disabled copy constructor.
static int pthread_timedjoin_np(pthread_t thread, void **retval, const struct timespec *abstime)
Implements a thread join function with timeout value.
ThreadPriority
Definition of different thread priority values.
Definition Thread.h:190
@ PRIORITY_IDLE
The thread runs if the system is idle.
Definition Thread.h:192
@ PRIORTY_BELOW_NORMAL
The thread has a priority below normal.
Definition Thread.h:194
@ PRIORTY_NORMAL
The thread has a normal priority.
Definition Thread.h:196
@ PRIORTY_ABOVE_NORMAL
The thread has a priority above normal.
Definition Thread.h:198
@ PRIORTY_HIGH
The thread has a high priority.
Definition Thread.h:200
static void sleep(unsigned int ms)
Sleeps the calling thread for a given time.
virtual ~Thread()
Destructs a thread object.
void internalThreadRun()
Platform independent internal thread function calling the external thread function.
static void giveUp()
Gives up the remaining thread time.
Thread(const std::string &name=std::string())
Creates a new thread object.
bool joinThread(const unsigned int timeout=(unsigned int)(-1))
Waits until this thread has been stopped.
std::pair< pthread_t, bool > TimedJoinPair
Definition of a pair holding a thread id and a boolean state.
Definition Thread.h:213
void stopThreadExplicitly(const unsigned int timeout=5000u)
Tries to stop the thread gracefully.
virtual void threadRun()=0
This function has to be overloaded in derived class.
static DWORD __stdcall staticThreadRun(void *data)
Internal thread function calling the external thread function.
static void * pthread_timedjoin_np_helper(void *threadData)
The helper function for the pthread_timedjoin_np() implementation.
static bool waitForValue(TObject &object, const TExpectedValue &expectedValue, const double timeout=-1.0)
Waits until an object/variable has an expected value.
Definition Thread.h:499
bool isThreadActive() const
Returns whether this thread is active.
static void * staticThreadRun(void *data)
Internal thread function calling the external thread function.
Thread(const unsigned int randomNumberSeedValue, const std::string &name=std::string())
Creates a new thread object.
bool shouldThreadStop() const
Returns whether this thread should stop.
static ThreadPriority threadPriority()
Returns the priority of the current thread.
This class implements a timestamp.
Definition Timestamp.h:36
bool hasTimePassed(const double seconds, const Timestamp &currentTimestamp=Timestamp(true)) const
Returns whether a specified amount of time has passed since this timestamp.
Definition Timestamp.h:290
The namespace covering the entire Ocean framework.
Definition Accessor.h:15