source: rrlib_thread/tThread.h @ 4:46a4150b6fd3

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

tLoopThread now allows to set whether to use application or system time after construction.
Cleaned up thread class code.

File size: 12.4 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
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 int64_t 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 = cur_thread;
128    if (result == NULL)   // unknown thread
129    {
130      result = GetCurThreadLocal().get();
131      if (result == NULL)
132      {
133        result = new tThread(true, false); // will be deleted by thread local
134        GetCurThreadLocal().reset(result); // safe because it's the same thread
135      }
136      cur_thread = result;
137    }
138    return *result;
139  }
140
141  bool GetDeleteOnCompletion() const
142  {
143    return delete_on_completion;
144  }
145
146  /*!
147   * \return Returns the rrlib ID of this Thread.
148   */
149  inline int 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(rrlib::logging::eLL_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   */
275  void SetPriority(int new_priority)
276  {
277    // TODO: currently does nothing
278    priority = new_priority;
279  }
280
281  /*!
282   * Makes this thread a real-time thread
283   * (sets priority appropriately)
284   */
285  void SetRealtime();
286
287  /*!
288   * The current thread will sleep for the specified amount of time.
289   * (Method will call wait() for longer durations => necessary for immediate reaction to time stretching + stopping threads will be quicker)
290   *
291   * \param wait_for Duration to wait
292   * \param use_application_time Is duration specified in "application time" instead of system time? (see rrlib/time/time.h).
293   * \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.
294   */
295  static void Sleep(const rrlib::time::tDuration& sleep_for, bool use_application_time, rrlib::time::tTimestamp wait_until = rrlib::time::cNO_TIME);
296
297  /*!
298   * Starts thread.
299   *
300   * Note, that a terminated thread cannot be restarted.
301   */
302  void Start();
303
304  /*!
305   * Tries to stop thread - but not by force
306   *
307   * Should be overridden by subclasses to provide proper implementations
308   */
309  virtual void StopThread();
310
311  /*!
312   * Tries to stop all known threads
313   */
314  static void StopThreads()
315  {
316    StopThreads(false);
317  }
318
319  /*!
320   * Returns whether an attempt was already made to stop all threads
321   */
322  static bool StoppingThreads()
323  {
324    return StopThreads(true);
325  }
326
327  /*!
328   * Hint to the scheduler that current thread is willing to yield.
329   */
330  static void Yield();
331
332//----------------------------------------------------------------------
333// Protected fields and methods
334//----------------------------------------------------------------------
335protected:
336
337  /*!
338   * Default constructor for derived classes.
339   *
340   * \param name Name of thread (optional)
341   */
342  tThread(const std::string& name = "");
343
344  /*!
345   * \param value New value for signal for stopping thread
346   */
347  void SetStopSignal(bool value)
348  {
349    stop_signal = value;
350  }
351
352//----------------------------------------------------------------------
353// Private fields and methods
354//----------------------------------------------------------------------
355private:
356
357  friend class internal::tLockStack;
358  friend class internal::tThreadCleanup;
359
360  /*!
361   * Thread state
362   */
363  enum class tState
364  {
365    NEW,             //!< Thread has not started yet
366    PREPARE_RUNNING, //!< Preparing to run thread
367    RUNNING,         //!< Thread is running
368    TERMINATED       //!< Thread has terminated
369  };
370
371  /*! ID that indicates that there's no valid thread id in thread local - needs to be different for windows */
372  static const int cNO_THREAD_ID = -1;
373
374  /*! Signal for stopping thread */
375  std::atomic<bool> stop_signal;
376
377  /*! Holds on to lock stack as long as thread exists */
378  std::shared_ptr<void> lock_stack;
379
380  /*! Id of Thread - generated by this class */
381  const int id;
382
383  /*! Name of Thread */
384  std::string name;
385
386  /*! Thread priority */
387  int priority;
388
389  /*! Current Thread state */
390  tState state;
391
392  /*! manager pointer to object itself */
393  std::shared_ptr<tThread> self;
394
395  /*! delete runnable/self when thread is completed and no more derived shared pointers point to object */
396  bool delete_on_completion;
397
398  /*! Signal for starting thread */
399  bool start_signal;
400
401  /*! Monitor for thread control and waiting with time stretching support */
402  tConditionVariable monitor;
403
404  /*! Threads own reference to threadList */
405  std::shared_ptr<internal::tVectorWithMutex<std::weak_ptr<tThread>>> thread_list_ref;
406
407  /*! Objects (shared pointers) that thread has locked (won't be deleted as long as thread exists) */
408  std::vector<std::shared_ptr<void>> locked_objects;
409
410  /*! Reference to current thread */
411  static __thread tThread* cur_thread;
412
413  /*!
414   * Determines order in which threads are stopped in StopThreads().
415   * Default is zero.
416   * Setting this to a higher value stops this thread later than the ones with lower values.
417   */
418  unsigned int longevity;
419
420  /*! True, if this is a thread that was not created via this class */
421  const bool unknown_thread;
422
423  /*! wrapped thread */
424  tWrappedThread wrapped_thread;
425
426  /*! pthread/whatever handle */
427  std::thread::native_handle_type handle;
428
429  /*! Number of threads that are joining */
430  std::atomic<int> joining_threads;
431
432
433  /*!
434   * Create object that handles threads not created via this class
435   * (we only have the two parameters to avoid ambiguities with the ordinary constructor - e.g. when passing a const char*)
436   */
437  tThread(bool anonymous, bool legion);
438
439  /*!
440   * Add thread to thread list
441   */
442  void AddToThreadList();
443
444  /*! Stores thread local information on current thread */
445  static boost::thread_specific_ptr<tThread>& GetCurThreadLocal();
446
447  /*!
448   * Newly created threads enter this method
449   */
450  static void Launch(tThread* thread_ptr);
451
452  /*!
453   * Called by method above
454   */
455  void Launcher();
456
457  /*!
458   * Helper method for joining
459   */
460  void PreJoin();
461
462  /*!
463   * Implementation of above methods - It's important to have the variable in the code to keep during static destruction
464   * (That's why we have this 2-in-1 implementation)
465   *
466   * Tries to stop all known threads
467   *
468   * \param query_only Query only whether threads have already been deleted?
469   * \return Returns whether an attempt was (already) made to stop all threads
470   */
471  static bool StopThreads(bool query_only);
472};
473
474//----------------------------------------------------------------------
475// End of namespace declaration
476//----------------------------------------------------------------------
477}
478}
479
480
481#endif
Note: See TracBrowser for help on using the repository browser.