source: rrlib_thread/tThread.h @ 30:fa354798480f

Last change on this file since 30:fa354798480f was 30:fa354798480f, checked in by Max Reichardt <mreichardt@…>, 5 years ago

Dependency to pthread library is now optional. Added RRLIB_SINGLE_THREADED #ifndefs to all places where they were still missing.

File size: 12.8 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 uint32_t tThreadId;
97
98#ifndef RRLIB_SINGLE_THREADED
99  typedef std::thread::native_handle_type tNativeHandle;
100#else
101  typedef tThreadId tNativeHandle;
102#endif
103
104  /*!
105   * Boundaries and default value for priorities
106   */
107  static const int cMIN_PRIORITY = 1;
108  static const int cDEFAULT_PRIORITY = 20;
109  static const int cMAX_PRIORITY = 49;
110
111  virtual ~tThread();
112
113#ifndef RRLIB_SINGLE_THREADED
114  /*!
115   * (convenience function)
116   *
117   * \return Current thread id
118   */
119  inline static tThreadId CurrentThreadId()
120  {
121    return CurrentThread().GetId();
122  }
123
124  /*!
125   * \return The thread that is currently executing.
126   *
127   * (Using the returned reference is only safe as long it is only used by the thread itself.
128   *  Otherwise the thread might have already been deleted.
129   *  Using CurrentThread().GetSharedPtr() is the safe alternative in this respect.)
130   */
131  inline static tThread& CurrentThread()
132  {
133    tThread* result = current_thread.pointer;
134    if (result == NULL)   // unknown thread
135    {
136      result = new tThread(true, false); // will be deleted by thread local
137      current_thread.pointer = result;
138    }
139    return *result;
140  }
141#endif
142
143  bool GetDeleteOnCompletion() const
144  {
145    return delete_on_completion;
146  }
147
148  /*!
149   * \return Returns the rrlib ID of this Thread.
150   *
151   * The thread id is unique for quite a long time (until 2^32 threads
152   * have been spawned. After that, it is guaranteed that all existing threads
153   * have different ids. Ids repeat less than every 2^31 threads)
154   * A thread id is never zero
155   */
156  inline tThreadId GetId() const
157  {
158    return id;
159  }
160
161  /*!
162   * \return Thread description for logging
163   */
164  std::string GetLogDescription() const;
165
166  /*!
167   * \return Thread description for logging
168   */
169  static inline const char* GetLogDescriptionStatic()
170  {
171    return "tThread";
172  }
173
174  /*!
175   * \return Monitor for thread control and waiting with time stretching support
176   */
177  inline tConditionVariable& GetMonitor()
178  {
179    return monitor;
180  }
181
182  /*!
183   * \return Name of this thread (if not previously set, this is 'Thread-<id>')
184   */
185  inline std::string GetName() const
186  {
187    return name;
188  }
189
190  /*!
191   * \return Native thread handle
192   */
193  inline tNativeHandle GetNativeHandle() const
194  {
195#ifndef RRLIB_SINGLE_THREADED
196    return handle;
197#else
198    return GetId();
199#endif
200  }
201
202  /*!
203   * \return Thread's current priority
204   */
205  int GetPriority() const
206  {
207    return priority;
208  }
209
210  /*!
211   * \return Relevant shared pointer regarding possible auto-deletion of thread
212   */
213  std::shared_ptr<tThread> GetSharedPtr()
214  {
215    return self;
216  }
217
218  /*!
219   * \return Is thread alive (started and not terminated)?
220   */
221  inline bool IsAlive() const
222  {
223    return state == tState::RUNNING || state == tState::PREPARE_RUNNING;
224  }
225
226  /*!
227   * \return Is the stop signal in order to stop this thread set?
228   */
229  inline bool IsStopSignalSet() const
230  {
231    return stop_signal;
232  }
233
234  /*!
235   * Waits for thread to terminate
236   */
237  void Join();
238
239  /*!
240   * \param obj Object (in shared pointer) that thread shall "lock"
241   * (it won't be deleted as long as thread exists)
242   * (pointers will be reset in reverse order of adding them)
243   */
244  void LockObject(std::shared_ptr<void> obj);
245
246  /*!
247   * Must be implemented by subclass.
248   * Called in new thread after it was started.
249   * When Run() ends the thread exits.
250   */
251  virtual void Run()
252  {
253    RRLIB_LOG_PRINT(WARNING, "No Run method implemented.");
254  }
255
256  /*!
257   * Setup thread so that it will automatically delete itself
258   * when it is finished and there are no further references
259   * to it
260   */
261  void SetAutoDelete()
262  {
263    delete_on_completion = true;
264  }
265
266  /*!
267   * \param longevity Determines order in which threads are stopped in StopThreads().
268   * Default is zero.
269   * Setting this to a higher value stops this thread later than the ones with lower values.
270   */
271  void SetLongevity(unsigned int longevity)
272  {
273    this->longevity = longevity;
274  }
275
276  /*!
277   * (May only be called, before thread is started!)
278   *
279   * \param name Name for thread
280   */
281  void SetName(const std::string& name);
282
283  /*!
284   * \param new_priority New priority for thread
285   * (values as for Linux' niceness: -20 Highest priority, 0 default, 19 Lowest)
286   * Can only be called for the current thread!
287   */
288  void SetPriority(int new_priority);
289
290  /*!
291   * Makes this thread a real-time thread
292   * (sets priority appropriately)
293   */
294  void SetRealtime();
295
296  /*!
297   * The current thread will sleep for the specified amount of time.
298   * (Method will call wait() for longer durations => necessary for immediate reaction to time stretching + stopping threads will be quicker)
299   *
300   * \param wait_for Duration to wait
301   * \param use_application_time Is duration specified in "application time" instead of system time? (see rrlib/time/time.h).
302   * \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.
303   */
304  static void Sleep(const rrlib::time::tDuration& sleep_for, bool use_application_time, rrlib::time::tTimestamp wait_until = rrlib::time::cNO_TIME);
305
306  /*!
307   * Starts thread.
308   *
309   * Note, that a terminated thread cannot be restarted.
310   */
311  void Start();
312
313  /*!
314   * Tries to stop thread - but not by force
315   *
316   * Should be overridden by subclasses to provide proper implementations
317   */
318  virtual void StopThread();
319
320  /*!
321   * Tries to stop all known threads
322   */
323  static void StopThreads()
324  {
325    StopThreads(false);
326  }
327
328  /*!
329   * Returns whether an attempt was already made to stop all threads
330   */
331  static bool StoppingThreads()
332  {
333    return StopThreads(true);
334  }
335
336  /*!
337   * Hint to the scheduler that current thread is willing to yield.
338   */
339  static void Yield();
340
341//----------------------------------------------------------------------
342// Protected fields and methods
343//----------------------------------------------------------------------
344protected:
345
346  /*!
347   * Default constructor for derived classes.
348   *
349   * \param name Name of thread (optional)
350   */
351  tThread(const std::string& name = "");
352
353  /*!
354   * \param value New value for signal for stopping thread
355   */
356  void SetStopSignal(bool value)
357  {
358    stop_signal = value;
359  }
360
361//----------------------------------------------------------------------
362// Private fields and methods
363//----------------------------------------------------------------------
364private:
365
366  friend class internal::tLockStack;
367  friend class internal::tThreadCleanup;
368
369  /*!
370   * Thread state
371   */
372  enum class tState
373  {
374    NEW,             //!< Thread has not started yet
375    PREPARE_RUNNING, //!< Preparing to run thread
376    RUNNING,         //!< Thread is running
377    TERMINATED       //!< Thread has terminated
378  };
379
380  /*! ID that indicates that there's no valid thread id in thread local - needs to be different for windows */
381  static const int cNO_THREAD_ID = -1;
382
383  /*! Signal for stopping thread */
384  std::atomic<bool> stop_signal;
385
386  /*! Holds on to lock stack as long as thread exists */
387  std::shared_ptr<void> lock_stack;
388
389  /*! Id of Thread - generated by this class */
390  const tThreadId id;
391
392  /*! Name of Thread */
393  std::string name;
394
395  /*! Thread priority */
396  int priority;
397
398  /*! Current Thread state */
399  tState state;
400
401  /*! manager pointer to object itself */
402  std::shared_ptr<tThread> self;
403
404  /*! delete runnable/self when thread is completed and no more derived shared pointers point to object */
405  bool delete_on_completion;
406
407  /*! Signal for starting thread */
408  bool start_signal;
409
410  /*! Monitor for thread control and waiting with time stretching support */
411  tConditionVariable monitor;
412
413  /*! Threads own reference to threadList */
414  std::shared_ptr<internal::tVectorWithMutex<std::weak_ptr<tThread>>> thread_list_ref;
415
416  /*! Objects (shared pointers) that thread has locked (won't be deleted as long as thread exists) */
417  std::vector<std::shared_ptr<void>> locked_objects;
418
419  /*! Holds thread pointer and has destructor for thread cleanup */
420  class tPointer
421  {
422  public:
423    tThread* pointer;
424    tPointer() : pointer(NULL) {}
425    ~tPointer();
426  };
427
428#ifndef RRLIB_SINGLE_THREADED
429  /*! Reference to current thread */
430  static thread_local tPointer current_thread;
431#endif
432
433  /*!
434   * Determines order in which threads are stopped in StopThreads().
435   * Default is zero.
436   * Setting this to a higher value stops this thread later than the ones with lower values.
437   */
438  unsigned int longevity;
439
440  /*! True, if this is a thread that was not created via this class */
441  const bool unknown_thread;
442
443#ifndef RRLIB_SINGLE_THREADED
444  /*! wrapped thread */
445  std::thread wrapped_thread;
446
447  /*! native thread handle */
448  tNativeHandle handle;
449#endif
450
451  /*! Number of threads that are joining */
452  std::atomic<int> joining_threads;
453
454
455  /*!
456   * Create object that handles threads not created via this class
457   * (we only have the two parameters to avoid ambiguities with the ordinary constructor - e.g. when passing a const char*)
458   */
459  tThread(bool anonymous, bool legion);
460
461  /*!
462   * Add thread to thread list
463   */
464  void AddToThreadList();
465
466  /*!
467   * Newly created threads enter this method
468   */
469  static void Launch(tThread* thread_ptr);
470
471  /*!
472   * Called by method above
473   */
474  void Launcher();
475
476  /*!
477   * Helper method for joining
478   */
479  void PreJoin();
480
481  /*!
482   * Implementation of above methods - It's important to have the variable in the code to keep during static destruction
483   * (That's why we have this 2-in-1 implementation)
484   *
485   * Tries to stop all known threads
486   *
487   * \param query_only Query only whether threads have already been deleted?
488   * \return Returns whether an attempt was (already) made to stop all threads
489   */
490  static bool StopThreads(bool query_only);
491};
492
493//----------------------------------------------------------------------
494// End of namespace declaration
495//----------------------------------------------------------------------
496}
497}
498
499
500#endif
Note: See TracBrowser for help on using the repository browser.