source: rrlib_thread/tThread.h @ 7:07dd445b7fac

Last change on this file since 7:07dd445b7fac was 7:07dd445b7fac, checked in by Max Reichardt <mreichardt@…>, 7 years ago

Added method to actually set niceness level of thread.
Thread id is now a unique 32 bit integer.
As discussed with Tobias, threads no longer catch all exceptions - so that they no longer 'get lost' and a stack trace is available.
If they are not handled somewhere else, the process terminates.

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