source: rrlib_thread/tThread.h @ 20:6a5ce655e1ab

Last change on this file since 20:6a5ce655e1ab was 20:6a5ce655e1ab, checked in by Max Reichardt <mreichardt@…>, 6 years ago

Removed boost dependency (replaced boost::thread_specific_ptr with standard thread_local)

File size: 12.6 KB
Line 
1//
2// You received this file as part of RRLib
3// Robotics Research Library
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    rrlib/thread/tThread.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-07-05
27 *
28 * \brief   Contains tThread
29 *
30 * \b tThread
31 *
32 * Convenient thread class.
33 * In some ways similar to Java Threads.
34 * Sleep method provides sleeping with respect to "application time".
35 */
36//----------------------------------------------------------------------
37#ifndef __rrlib__thread__tThread_h__
38#define __rrlib__thread__tThread_h__
39
40//----------------------------------------------------------------------
41// External includes (system with <>, local with "")
42//----------------------------------------------------------------------
43#include <thread>
44#include <atomic>
45#include "rrlib/logging/messages.h"
46#include "rrlib/time/time.h"
47
48//----------------------------------------------------------------------
49// Internal includes with ""
50//----------------------------------------------------------------------
51#include "rrlib/thread/tConditionVariable.h"
52
53//----------------------------------------------------------------------
54// Namespace declaration
55//----------------------------------------------------------------------
56namespace rrlib
57{
58namespace thread
59{
60
61//----------------------------------------------------------------------
62// Forward declarations / typedefs / enums
63//----------------------------------------------------------------------
64namespace internal
65{
66
67template <typename T>
68struct tVectorWithMutex
69{
70  std::vector<T> vec;
71  tOrderedMutex obj_mutex;
72  tVectorWithMutex(int lock_order) : vec(), obj_mutex("rrlib_thread tVectorWithMutex", lock_order) {}
73};
74
75class tThreadCleanup;
76class tThreadDeleter;
77
78} // namespace internal
79
80//----------------------------------------------------------------------
81// Class declaration
82//----------------------------------------------------------------------
83//! Convenient thread class
84/*!
85 * In some ways similar to Java Threads.
86 * Sleep method provides sleeping with respect to "application time".
87 */
88class tThread : public tMutex
89{
90
91//----------------------------------------------------------------------
92// Public methods and typedefs
93//----------------------------------------------------------------------
94public:
95
96  typedef std::thread tWrappedThread;
97  typedef uint32_t tThreadId;
98
99  /*!
100   * Boundaries and default value for priorities
101   */
102  static const int cMIN_PRIORITY = 1;
103  static const int cDEFAULT_PRIORITY = 20;
104  static const int cMAX_PRIORITY = 49;
105
106  virtual ~tThread();
107
108  /*!
109   * (convenience function)
110   *
111   * \return Current thread id
112   */
113  inline static tThreadId CurrentThreadId()
114  {
115    return CurrentThread().GetId();
116  }
117
118  /*!
119   * \return The thread that is currently executing.
120   *
121   * (Using the returned reference is only safe as long it is only used by the thread itself.
122   *  Otherwise the thread might have already been deleted.
123   *  Using CurrentThread().GetSharedPtr() is the safe alternative in this respect.)
124   */
125  inline static tThread& CurrentThread()
126  {
127    tThread* result = current_thread.pointer;
128    if (result == NULL)   // unknown thread
129    {
130      result = new tThread(true, false); // will be deleted by thread local
131      current_thread.pointer = result;
132    }
133    return *result;
134  }
135
136  bool GetDeleteOnCompletion() const
137  {
138    return delete_on_completion;
139  }
140
141  /*!
142   * \return Returns the rrlib ID of this Thread.
143   *
144   * The thread id is unique for quite a long time (until 2^32 threads
145   * have been spawned. After that, it is guaranteed that all existing threads
146   * have different ids. Ids repeat less than every 2^31 threads)
147   * A thread id is never zero
148   */
149  inline tThreadId GetId() const
150  {
151    return id;
152  }
153
154  /*!
155   * \return Thread description for logging
156   */
157  std::string GetLogDescription() const;
158
159  /*!
160   * \return Thread description for logging
161   */
162  static inline const char* GetLogDescriptionStatic()
163  {
164    return "tThread";
165  }
166
167  /*!
168   * \return Monitor for thread control and waiting with time stretching support
169   */
170  inline tConditionVariable& GetMonitor()
171  {
172    return monitor;
173  }
174
175  /*!
176   * \return Name of this thread (if not previously set, this is 'Thread-<id>')
177   */
178  inline std::string GetName() const
179  {
180    return name;
181  }
182
183  /*!
184   * \return Native thread handle
185   */
186  inline std::thread::native_handle_type GetNativeHandle() const
187  {
188    return handle;
189  }
190
191  /*!
192   * \return Thread's current priority
193   */
194  int GetPriority() const
195  {
196    return priority;
197  }
198
199  /*!
200   * \return Relevant shared pointer regarding possible auto-deletion of thread
201   */
202  std::shared_ptr<tThread> GetSharedPtr()
203  {
204    return self;
205  }
206
207  /*!
208   * \return Is thread alive (started and not terminated)?
209   */
210  inline bool IsAlive() const
211  {
212    return state == tState::RUNNING || state == tState::PREPARE_RUNNING;
213  }
214
215  /*!
216   * \return Is the stop signal in order to stop this thread set?
217   */
218  inline bool IsStopSignalSet() const
219  {
220    return stop_signal;
221  }
222
223  /*!
224   * Waits for thread to terminate
225   */
226  void Join();
227
228  /*!
229   * \param obj Object (in shared pointer) that thread shall "lock"
230   * (it won't be deleted as long as thread exists)
231   * (pointers will be reset in reverse order of adding them)
232   */
233  void LockObject(std::shared_ptr<void> obj);
234
235  /*!
236   * Must be implemented by subclass.
237   * Called in new thread after it was started.
238   * When Run() ends the thread exits.
239   */
240  virtual void Run()
241  {
242    RRLIB_LOG_PRINT(WARNING, "No Run method implemented.");
243  }
244
245  /*!
246   * Setup thread so that it will automatically delete itself
247   * when it is finished and there are no further references
248   * to it
249   */
250  void SetAutoDelete()
251  {
252    delete_on_completion = true;
253  }
254
255  /*!
256   * \param longevity Determines order in which threads are stopped in StopThreads().
257   * Default is zero.
258   * Setting this to a higher value stops this thread later than the ones with lower values.
259   */
260  void SetLongevity(unsigned int longevity)
261  {
262    this->longevity = longevity;
263  }
264
265  /*!
266   * (May only be called, before thread is started!)
267   *
268   * \param name Name for thread
269   */
270  void SetName(const std::string& name);
271
272  /*!
273   * \param new_priority New priority for thread
274   * (values as for Linux' niceness: -20 Highest priority, 0 default, 19 Lowest)
275   * Can only be called for the current thread!
276   */
277  void SetPriority(int new_priority);
278
279  /*!
280   * Makes this thread a real-time thread
281   * (sets priority appropriately)
282   */
283  void SetRealtime();
284
285  /*!
286   * The current thread will sleep for the specified amount of time.
287   * (Method will call wait() for longer durations => necessary for immediate reaction to time stretching + stopping threads will be quicker)
288   *
289   * \param wait_for Duration to wait
290   * \param use_application_time Is duration specified in "application time" instead of system time? (see rrlib/time/time.h).
291   * \param wait_until Time point until to wait (optional). If specified, this function won't need call clock's now() in case application time is used.
292   */
293  static void Sleep(const rrlib::time::tDuration& sleep_for, bool use_application_time, rrlib::time::tTimestamp wait_until = rrlib::time::cNO_TIME);
294
295  /*!
296   * Starts thread.
297   *
298   * Note, that a terminated thread cannot be restarted.
299   */
300  void Start();
301
302  /*!
303   * Tries to stop thread - but not by force
304   *
305   * Should be overridden by subclasses to provide proper implementations
306   */
307  virtual void StopThread();
308
309  /*!
310   * Tries to stop all known threads
311   */
312  static void StopThreads()
313  {
314    StopThreads(false);
315  }
316
317  /*!
318   * Returns whether an attempt was already made to stop all threads
319   */
320  static bool StoppingThreads()
321  {
322    return StopThreads(true);
323  }
324
325  /*!
326   * Hint to the scheduler that current thread is willing to yield.
327   */
328  static void Yield();
329
330//----------------------------------------------------------------------
331// Protected fields and methods
332//----------------------------------------------------------------------
333protected:
334
335  /*!
336   * Default constructor for derived classes.
337   *
338   * \param name Name of thread (optional)
339   */
340  tThread(const std::string& name = "");
341
342  /*!
343   * \param value New value for signal for stopping thread
344   */
345  void SetStopSignal(bool value)
346  {
347    stop_signal = value;
348  }
349
350//----------------------------------------------------------------------
351// Private fields and methods
352//----------------------------------------------------------------------
353private:
354
355  friend class internal::tLockStack;
356  friend class internal::tThreadCleanup;
357
358  /*!
359   * Thread state
360   */
361  enum class tState
362  {
363    NEW,             //!< Thread has not started yet
364    PREPARE_RUNNING, //!< Preparing to run thread
365    RUNNING,         //!< Thread is running
366    TERMINATED       //!< Thread has terminated
367  };
368
369  /*! ID that indicates that there's no valid thread id in thread local - needs to be different for windows */
370  static const int cNO_THREAD_ID = -1;
371
372  /*! Signal for stopping thread */
373  std::atomic<bool> stop_signal;
374
375  /*! Holds on to lock stack as long as thread exists */
376  std::shared_ptr<void> lock_stack;
377
378  /*! Id of Thread - generated by this class */
379  const tThreadId id;
380
381  /*! Name of Thread */
382  std::string name;
383
384  /*! Thread priority */
385  int priority;
386
387  /*! Current Thread state */
388  tState state;
389
390  /*! manager pointer to object itself */
391  std::shared_ptr<tThread> self;
392
393  /*! delete runnable/self when thread is completed and no more derived shared pointers point to object */
394  bool delete_on_completion;
395
396  /*! Signal for starting thread */
397  bool start_signal;
398
399  /*! Monitor for thread control and waiting with time stretching support */
400  tConditionVariable monitor;
401
402  /*! Threads own reference to threadList */
403  std::shared_ptr<internal::tVectorWithMutex<std::weak_ptr<tThread>>> thread_list_ref;
404
405  /*! Objects (shared pointers) that thread has locked (won't be deleted as long as thread exists) */
406  std::vector<std::shared_ptr<void>> locked_objects;
407
408  /*! Holds thread pointer and has destructor for thread cleanup */
409  class tPointer
410  {
411  public:
412    tThread* pointer;
413    tPointer() : pointer(NULL) {}
414    ~tPointer();
415  };
416
417  /*! Reference to current thread */
418  static thread_local tPointer current_thread;
419
420  /*!
421   * Determines order in which threads are stopped in StopThreads().
422   * Default is zero.
423   * Setting this to a higher value stops this thread later than the ones with lower values.
424   */
425  unsigned int longevity;
426
427  /*! True, if this is a thread that was not created via this class */
428  const bool unknown_thread;
429
430  /*! wrapped thread */
431  tWrappedThread wrapped_thread;
432
433  /*! pthread/whatever handle */
434  std::thread::native_handle_type handle;
435
436  /*! Number of threads that are joining */
437  std::atomic<int> joining_threads;
438
439
440  /*!
441   * Create object that handles threads not created via this class
442   * (we only have the two parameters to avoid ambiguities with the ordinary constructor - e.g. when passing a const char*)
443   */
444  tThread(bool anonymous, bool legion);
445
446  /*!
447   * Add thread to thread list
448   */
449  void AddToThreadList();
450
451  /*!
452   * Newly created threads enter this method
453   */
454  static void Launch(tThread* thread_ptr);
455
456  /*!
457   * Called by method above
458   */
459  void Launcher();
460
461  /*!
462   * Helper method for joining
463   */
464  void PreJoin();
465
466  /*!
467   * Implementation of above methods - It's important to have the variable in the code to keep during static destruction
468   * (That's why we have this 2-in-1 implementation)
469   *
470   * Tries to stop all known threads
471   *
472   * \param query_only Query only whether threads have already been deleted?
473   * \return Returns whether an attempt was (already) made to stop all threads
474   */
475  static bool StopThreads(bool query_only);
476};
477
478//----------------------------------------------------------------------
479// End of namespace declaration
480//----------------------------------------------------------------------
481}
482}
483
484
485#endif
Note: See TracBrowser for help on using the repository browser.