source: rrlib_thread/tThread.h @ 0:c2492b69e880

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

Initial commit. These are refactored thread classes that were moved out of finroc_core_utils.

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