HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_Thread.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_Thread.h ( UT Library, C++)
7  *
8  * COMMENTS: Generic thread class.
9  * The owner of the thread can do things like:
10  *
11  * killThread() - Stop execution of thread
12  * waitThread() - Wait until thread finishes execution
13  * suspendThread() - Suspend execution of thread
14  * restartThread() - Restart a stopped thread
15  *
16  * TODO: It might be nice to have a way to get the exit status of a thread.
17  */
18 
19 #ifndef __UT_Thread__
20 #define __UT_Thread__
21 
22 #include "UT_API.h"
23 #include "UT_Array.h"
24 #include "UT_Assert.h"
25 #include "UT_StringHolder.h"
26 #include "UT_UniquePtr.h"
27 
28 #include <SYS/SYS_Deprecated.h>
30 #include <SYS/SYS_Types.h>
31 
32 #include <stdlib.h>
33 
34 #include <thread>
35 #include <tuple>
36 
37 #if defined(WIN32)
38 # include <intrin.h>
39  typedef int ut_thread_id_t;
40 #elif defined(USE_PTHREADS)
41 # include <sched.h>
42 # include <pthread.h>
43  typedef pthread_t ut_thread_id_t;
44 #else
45  #error Unsupported Platform for UT_Thread
46 #endif
47 
48 #define UT_INVALID_THREAD_ID ((ut_thread_id_t)0)
49 
50 // some stack size defines
51 #define UT_THREAD_DEFAULT_STACK_SIZE (8U*1024U*1024U)
52 #define UT_THREAD_SMALL_STACK_SIZE (1U*1024U*1024U)
53 
54 typedef void *(*UTthreadFunc)(void*);
55 
56 // forward declarations
57 class UT_TaskScope;
58 
60 {
61 public:
62  // The destructor will wait until the thread is idle before it completes
63  // If you wish to kill the thread, call killThread() first.
64  virtual ~UT_Thread();
65 
66  UT_Thread(const UT_Thread &) = delete;
67  UT_Thread &operator=(const UT_Thread &) = delete;
68 
69  // This enum specifies the current state for a persistent thread. The
70  // thread will typically be running or idle. If the thread is idle, it's
71  // behaviour will be determined by the SpinState.
72  enum State
73  {
75  ThreadRunning
76  };
77 
78  // // The thread status determines how the thread will behave once the
79  // callback function is completed:
80  // ThreadSingleRun - The thread cannot be restarted
81  // ThreadLowUsage - The thread will yield cycles while idle
82  //
83  enum SpinMode
84  {
87  };
88 
89  /// Allocate a new thread
90  /// @param spin_mode Use ThreadSingleRun to have it exit when the thread
91  /// callback is finished. Otherwise, ThreadLowUsage
92  /// will cause the thread to loop back and wait for
93  /// more startThread() calls to run different thread
94  /// callbacks in the same thread.
95  static UT_Thread *allocThread(SpinMode spin_mode);
96 
97  static int getNumProcessors();
98 
99  /// This is only valid in debug builds
100  static int activeThreadCount();
101 
102  /// Reset the number of threads that is used by Houdini. This will reread
103  /// the HOUDINI_MAXTHREADS setting.
104  /// @note There should be no active tasks when this is called.
105  /// @note Only call this from the MAIN THREAD!
106  static void resetNumProcessors();
107 
108  // getMyThreadId() is inlined for speed if we're using pthreads.
109 #if defined(USE_PTHREADS)
110  static ut_thread_id_t getMyThreadId() { return pthread_self(); }
111 #else
112  static ut_thread_id_t getMyThreadId();
113 #endif
114 
115  static ut_thread_id_t getMainThreadId();
116  static int getMainSequentialThreadId();
117  static inline int isMainThread()
118  {
119  return getMyThreadId() == getMainThreadId();
120  }
121 
122  /// Returns true if the current thread is a UT_Thread.
123  /// Returns false if the current thread is either the main thread
124  /// or a TBB thread.
125  static bool isUTThreadCurrent();
126 
127  /// Returns true iff the current thread is allowed to create more tasks.
128  /// This is sometimes disabled, to avoid needing to create a UT_TaskArena
129  /// for small cases that won't get much benefit from threading.
130  /// This should be checked by anything using tbb::parallel_for,
131  /// tbb::parallel_invoke, or anything else creating TBB tasks.
132  static bool isThreadingEnabled();
133 
134  /// This is used to disable (false) threading for the current thread,
135  /// to avoid needing to create a UT_TaskArena for small cases that won't
136  /// get much benefit from threading. It returns if it was enabled before.
137  /// It is also used to re-enable (true) threading for the current thread.
138  static bool setThreadingEnabled(bool will_be_enabled);
139 
141  {
142  public:
144  : myPreviouslyEnabled(setThreadingEnabled(false))
145  {}
147  {
148  if (myPreviouslyEnabled)
149  setThreadingEnabled(true);
150  }
151  private:
152  const bool myPreviouslyEnabled;
153  };
154 
155  // CPU pauses the task for a given number of cycles
156  static inline void pause(uint cycles)
157  {
158  for(uint i = 0; i < cycles; i++)
159 #if defined(USE_PTHREADS)
160 #if defined(ARM64)
161  __asm__ __volatile__("yield;");
162 #else
163  __asm__ __volatile__("pause;");
164 #endif
165 #else
166  _mm_pause();
167 #endif
168  }
169  // Yields the task to the scheduler.
170 #if defined(USE_PTHREADS)
171  static inline void yield(bool higher_only=false)
172  {
173  if (higher_only)
174  {
175  ::sched_yield();
176  }
177  else
178  {
179  // Sleep for 100ns. That's 10,000,000 sleep
180  // cycles a second (in case you don't have a
181  // calculator :-)
182  struct timespec ts = {0,100};
183  ::nanosleep(&ts, 0);
184  }
185  }
186 #else
187  static void yield(bool higher_only=false);
188 #endif
189 
190  /// This function has been deprecated. Use SYS_SequentialThreadIndex::get()
191  /// or SYSgetSTID instead.
192  static int SYS_DEPRECATED(12.5) getMySequentialThreadIndex()
193  { return SYS_SequentialThreadIndex::get(); }
194 
195  /// Configure the global number of tasks used by the system
196  /// - The default value of 0 uses the number of logical cores on the system
197  /// - A negative value wraps it from the number of logical cores.
198  /// eg. -1 will use all cores except for 1.
199  /// - If the negative value exceeds the number of logical cores, it is
200  /// clamped to a value of 1.
201  /// @note Only call this in the main thread when there are no tasks active.
202  /// @note This function is NOT thread-safe.
203  static void configureMaxThreads(int maxthreads = 0);
204 
205  /// Configure the default stack size for threads
206  /// - A value of 0 uses the stack size of the main thread
207  /// - A value larger than 0 will use that specific stack size
208  /// @note Only call this in the main thread when there are no tasks active.
209  /// @note This function is NOT thread-safe.
210  static void configureThreadStackSize(int stacksize);
211 
212  /// Return the current running thread's stack size
213  static int getCurrentThreadStackSize();
214 
215  /// Sets the current thread to minimum priority according to the rules
216  /// of the platform. This function fails if called on a thread that is
217  /// not a running UT_Thread.
218  /// Returns true if the operation was successful, otherwise returns false.
219  static bool minimizeThisThreadPriority();
220 
221 #if defined(MBSD)
222  /// Sets the quality of service (QoS) class of a thread. This is used by
223  /// the macOS scheduler to prioritize certain tasks.
224  /// @note Calling this is optional, however if it is called, it must be
225  /// called before startThread()
226  /// @note This method is only available on macOS
227  void setQoS(qos_class_t qos);
228 
229  /// Returns the quality of service (QoS) class of a thread.
230  /// @note This method is only available on macOS
231  /// @see setQoS()
232  qos_class_t getQoS() const;
233 #endif
234 
236  {
237  public:
240 
241  DisableGlobalControl(const DisableGlobalControl &) = delete;
243  };
244 
245  // Start the thread running. If the thread is not in idle state, the
246  // thread will wait until it's in idle before starting. If the thread
247  // doesn't exist yet, it will be created.
248  virtual bool startThread(UTthreadFunc func, void *data,
249  int stacksize) = 0;
250 
251  // Use the global thread stack size set by configureMaxThreads()
252  bool startThread(UTthreadFunc func, void *data);
253 
254  // This method is called when the thread function is first entered.
255  // By default it does nothing but some sub-classes may need this.
256  virtual void threadStarted();
257 
258  // This method is called when the thread function is returned from.
259  // By default it sets the state to idle.
260  virtual void threadEnded();
261 
262 
263  // Some thread architectures have very expensive resources (i.e. sproc()
264  // threads). While these threads spin (are idle), they consume system
265  // resources. This method will let the user know whether the threads are
266  // resource hogs (so that if they spin for a long time, they could
267  // possibley be cleaned up).
268  virtual int isResourceHog() const;
269 
270  // For persistent threads (which get restarted)
271  virtual State getState();
272  virtual SpinMode getSpinMode();
273  virtual void waitForState(State desired) = 0;
274  virtual void setSpinMode(SpinMode spin_mode);
275 
276  // Assign a name to the thread. This makes it easier to find in a debugger.
277  // This should be called before the thread is started.
278  void setThreadName(const UT_StringHolder &name);
279 
280  // Terminate the thread process
281  virtual void killThread() = 0;
282 
283  // If it's possible to perform these tasks, the return code will be 1. If
284  // not, the return code will be 0.
285  virtual int suspendThread() = 0;
286  virtual int restartThread() = 0;
287 
288  int isActive()
289  { return waitThread(0); }
290 
291  /// NOTE: This level doesn't own any data apart from itself.
292  virtual int64 getMemoryUsage(bool inclusive) const = 0;
293 
294 protected:
295  // System dependent internal functions.
296  // waitThread() returns 1 if the thread is still active (i.e. exists) and
297  // should return 0 if the thread doesn't exist. If waitThread detects
298  // that the thread no longer exists, it should do appropriate cleanup.
299  virtual int waitThread(int block=1) = 0;
300 
301  // Quick check to see that the thread is really active
302  virtual int isValid();
303 
304  // This method can be used to kill an idle process.
305  void killIdle();
306 
307  static void *threadWrapper(void *data);
308 
309  // Internally used to change the state safely.
310  virtual void setState(State state) = 0;
311 
312  volatile State myState;
315  void *myCBData;
316 
318 
320 
321 #if defined(MBSD)
322  // The quality of service (QoS) of this thread for the macOS scheduler
323  qos_class_t myQoS;
324 #endif
325 
326  UT_Thread(SpinMode spin_mode);
327 
328 private:
329  friend class UT_SubSystem;
330 
331  static void onExit_();
332 };
333 
334 // For debugging, the following uses a single thread (i.e. is not
335 // multi-threaded)
337 {
338 public:
339  UT_NullThread();
340  ~UT_NullThread() override;
341 
342  UT_NullThread(const UT_NullThread &) = delete;
343  UT_NullThread &operator=(const UT_NullThread &) = delete;
344 
345  bool startThread(UTthreadFunc func, void *data,
346  int stacksize) override;
347  void killThread() override;
348  int waitThread(int block) override;
349  void waitForState(State) override;
350 
351  int suspendThread() override;
352  int restartThread() override;
353 
354  int64 getMemoryUsage(bool inclusive) const override
355  {
356  int64 mem = inclusive ? sizeof(*this) : 0;
357  // NOTE: We don't know how much memory Windows uses,
358  // so we can't count it.
359  return mem;
360  }
361 
362 protected:
363  void setState(State state) override;
364 };
365 
366 
368 {
369 public:
370  UT_ThreadSet(int nthreads=-1, int null_thread_if_1_cpu = 0);
371  ~UT_ThreadSet();
372 
373  UT_ThreadSet(const UT_ThreadSet &) = delete;
374  UT_ThreadSet &operator=(const UT_ThreadSet &) = delete;
375 
377  {
378  myFunc = func;
379  }
380  void setUserData(void *user_data_array, size_t structlen)
381  {
382  myUserData = user_data_array;
383  myUserDataInc = structlen;
384  }
385  void setUserData(void *user_data)
386  {
387  myUserData = user_data;
388  myUserDataInc = 0;
389  }
390 
391  void reuse(UT_Thread::SpinMode spin_mode);
392  void go();
393  int wait(int block=1);
394 
395  int getNumThreads() const { return myThreadCount; }
396  UT_Thread *getThread(int which);
397  UT_Thread *operator[](int which)
398  {
399  UT_ASSERT_P(which < myThreadCount);
400  return myThreads[which];
401  }
402 
403 protected:
407  void *myUserData;
409 };
410 
412 {
413 public:
415  {
416  NON_BLOCKING = 0, // Only assign thread if one is available
417  BLOCKING = 1, // Block until a thread is free.
418  DYNAMIC = 2 // If no threads are availble, create a new one.
419  };
420 
421  // similar to UT_ThreadSet, but a bit simpler. Called UT_ThreadFarm
422  // because it farms out the next available thread. You also don't need to
423  // match the number of data chunks to the number of threads.
424  // ie.
425  // farm = new UT_ThreadFarm(4);
426  // while(!done) {
427  // thread = farm->nextThread();
428  // thread->startThread(entrypoint, mydata);
429  // }
430  // farm->wait();
431 
432  UT_ThreadFarm(int nthreads=-1);
433  ~UT_ThreadFarm();
434 
435  UT_ThreadFarm(const UT_ThreadFarm &) = delete;
436  UT_ThreadFarm &operator=(const UT_ThreadFarm &) = delete;
437 
438  // waits for the next available thread, (or returns null if none are
439  // available and block = 0). thread_index will contain the thread index
440  // if you pass it a non-null pointer.
441  UT_Thread *nextThread(int *thread_index =0,
442  AssignmentStyle style = BLOCKING);
443 
444  // waits until all threads are finished (or, returns 0 if not finished and
445  // block = 0).
446  int wait(int block = 1);
447 
448  // deletes threads in the thread farm. if kill=1 the threads are killed before
449  // cleanup, otherwise wait(1) is called.
450  void cleanup(int kill = 0);
451 
452  int getEntries() const { return myThreadCount; }
454  {
455  UT_ASSERT_P(index < myThreadCount);
456  return myThreads[index];
457  }
458 
459 protected:
460  void addThreads(int thread_count);
461 
464 };
465 
466 // Gradual backoff when there's thread contention.
468 {
469 public:
470  UT_ThreadBackoff() : myCycles(1) {}
471 
472  static const uint cycles_for_noop = 4;
473  static const uint cycles_for_pause = cycles_for_noop * 4;
474  static const uint cycles_for_yield_higher = cycles_for_pause * 2;
475  static const uint cycles_for_yield_all = cycles_for_yield_higher * 2;
476 
477  // Same thresholds as hboost::detail::yield(), but different behaviour
478  void wait()
479  {
480  if (myCycles > cycles_for_yield_all)
481  {
482  // Yield the thread completely, to any and all comers.
483  UT_Thread::yield(false);
484  return;
485  }
486 
487  if (myCycles <= cycles_for_noop)
488  {
489  // Noop.
490  }
491  else if (myCycles <= cycles_for_pause)
492  {
493  UT_Thread::pause(myCycles);
494  }
495  else if (myCycles <= cycles_for_yield_higher)
496  {
497  UT_Thread::yield(true);
498  }
499  myCycles += (myCycles+1)>>1;
500  }
501 
502  void reset()
503  {
504  myCycles = 1;
505  }
506 
507 private:
508  uint myCycles;
509 };
510 
511 namespace UT
512 {
513 namespace detail
514 {
516 {
517 public:
518  ThreadInit();
519  ~ThreadInit();
520 
521  ThreadInit(const ThreadInit &) = delete;
522  ThreadInit &operator=(const ThreadInit &) = delete;
523 
524 };
525 } // namespace detail
526 } // namespace UT
527 
528 class UT_StdThread : public std::thread
529 {
530 public:
531  UT_StdThread() = default;
532  template <typename Func, typename... Args>
533  UT_StdThread(Func &&func, Args &&... args)
534  : std::thread(
535  WrapFunctor<Func, Args...>(std::forward<Func>(func)),
536  std::forward<Args>(args)...)
537  {
538  }
539 
540  UT_StdThread(const UT_StdThread&) = delete;
541  UT_StdThread& operator=(const UT_StdThread&) = delete;
542  UT_StdThread(UT_StdThread&&) = default;
543  UT_StdThread& operator=(UT_StdThread&&) = default;
544 
545 private:
546  template <typename Func, typename... Args>
547  class WrapFunctor
548  {
549  public:
550  WrapFunctor(Func&& func)
551  : myFunc(std::move(func))
552  {
553  }
554 
555  decltype(auto) operator()(Args&&... args) const
556  {
558  return myFunc(std::forward<Args>(args)...);
559  }
560  private:
561  Func myFunc;
562  };
563 };
564 
566 {
567 public:
569 
570  explicit UT_StdThreadGroup(int nthreads = -1)
571  {
572  if (nthreads < 1)
573  nthreads = UT_Thread::getNumProcessors();
574 
575  myThreads.setSize(nthreads);
576  }
577 
578  UT_StdThreadGroup(const UT_StdThreadGroup&) = delete;
580 
581  thread_t& get(int idx)
582  {
583  return myThreads(idx);
584  }
585  const thread_t& get(int idx) const
586  {
587  return myThreads(idx);
588  }
590  {
591  return myThreads[idx];
592  }
593  const thread_t& operator[](int idx) const
594  {
595  return myThreads[idx];
596  }
597  bool joinable() const
598  {
599  for (auto&& t : myThreads)
600  {
601  if (!t.joinable())
602  return false;
603  }
604  return true;
605  }
606  bool joinable(int idx) const
607  {
608  return get(idx).joinable();
609  }
610  void join()
611  {
612  for (auto&& t : myThreads)
613  {
614  if (t.joinable())
615  t.join();
616  }
617  }
618 private:
619  UT_Array<thread_t> myThreads;
620 };
621 
622 // This function has been deprecated. Use SYSgetSTID instead.
623 static inline int SYS_DEPRECATED(12.5)
624 UTgetSTID()
625 {
627 }
628 
629 #endif
volatile State myState
Definition: UT_Thread.h:312
int getNumThreads() const
Definition: UT_Thread.h:395
void setUserData(void *user_data)
Definition: UT_Thread.h:385
#define SYS_DEPRECATED(__V__)
int64 getMemoryUsage(bool inclusive) const override
NOTE: This level doesn't own any data apart from itself.
Definition: UT_Thread.h:354
UT_StdThread()=default
The subsystem to initialize and cleanup UT.
Definition: UT_SubSystem.h:121
virtual int restartThread()=0
int myThreadCount
Definition: UT_Thread.h:404
void *(* UTthreadFunc)(void *)
Definition: UT_Thread.h:54
UTthreadFunc myCallback
Definition: UT_Thread.h:314
UT_StdThread(Func &&func, Args &&...args)
Definition: UT_Thread.h:533
UT_Thread * operator[](int index)
Definition: UT_Thread.h:453
SpinMode mySpinMode
Definition: UT_Thread.h:313
void * myCBData
Definition: UT_Thread.h:315
#define UT_API
Definition: UT_API.h:14
UT_StringHolder myName
Definition: UT_Thread.h:317
bool joinable(int idx) const
Definition: UT_Thread.h:606
UT_StdThread & operator=(const UT_StdThread &)=delete
UT_Thread * operator[](int which)
Definition: UT_Thread.h:397
int getEntries() const
Definition: UT_Thread.h:452
bool joinable() const
Definition: UT_Thread.h:597
UT_Thread ** myThreads
Definition: UT_Thread.h:405
thread_t & operator[](int idx)
Definition: UT_Thread.h:589
virtual void setState(State state)=0
UT_StdThreadGroup & operator=(const UT_StdThreadGroup &)=delete
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:164
int myThreadCount
Definition: UT_Thread.h:462
static int getNumProcessors()
virtual void waitForState(State desired)=0
void setFunc(UTthreadFunc func)
Definition: UT_Thread.h:376
virtual bool startThread(UTthreadFunc func, void *data, int stacksize)=0
UT_Thread & operator=(const UT_Thread &)=delete
long long int64
Definition: SYS_Types.h:116
virtual void killThread()=0
GLuint const GLchar * name
Definition: glcorearb.h:786
int64 myUserDataInc
Definition: UT_Thread.h:408
const UT_TaskScope * myTaskScope
Definition: UT_Thread.h:319
const thread_t & operator[](int idx) const
Definition: UT_Thread.h:593
FS_API bool cleanup(UT_StringArray &removed, UT_StringArray &error_files, exint &memory_freed, bool dry_run, const char *override_path=nullptr)
GLdouble t
Definition: glad.h:2397
virtual int suspendThread()=0
*tasks wait()
**Note that the tasks the is the thread number *for the or if it s being executed by a non pool thread(this *can happen in cases where the whole pool is occupied and the calling *thread contributes to running the work load).**Thread pool.Have fun
static int isMainThread()
Definition: UT_Thread.h:117
GLenum func
Definition: glcorearb.h:783
LeafData & operator=(const LeafData &)=delete
UTthreadFunc myFunc
Definition: UT_Thread.h:406
GLuint index
Definition: glcorearb.h:786
void yield() noexcept
Definition: thread.h:94
UT_Thread ** myThreads
Definition: UT_Thread.h:463
static void pause(uint cycles)
Definition: UT_Thread.h:156
**If you just want to fire and args
Definition: thread.h:618
int isActive()
Definition: UT_Thread.h:288
static void yield(bool higher_only=false)
virtual int waitThread(int block=1)=0
void * myUserData
Definition: UT_Thread.h:407
unsigned int uint
Definition: SYS_Types.h:45
state
Definition: core.h:2289
void setUserData(void *user_data_array, size_t structlen)
Definition: UT_Thread.h:380
Definition: format.h:1821
UT_StdThreadGroup(int nthreads=-1)
Definition: UT_Thread.h:570