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  * niceThread() - Prioritize thread (0 low priority, 100 high)
16  *
17  * TODO: It might be nice to have a way to get the exit status of a thread.
18  */
19 
20 #ifndef __UT_Thread__
21 #define __UT_Thread__
22 
23 #include "UT_API.h"
24 #include "UT_Assert.h"
25 
26 #include <SYS/SYS_Deprecated.h>
28 #include <SYS/SYS_Types.h>
29 
30 #include <stdlib.h>
31 
32 #if defined(WIN32)
33 # include <intrin.h>
34  typedef int ut_thread_id_t;
35 #elif defined(USE_PTHREADS)
36 # include <sched.h>
37 # include <pthread.h>
38  typedef pthread_t ut_thread_id_t;
39 #else
40  #error Unsupported Platform for UT_Thread
41 #endif
42 
43 #define UT_INVALID_THREAD_ID ((ut_thread_id_t)0)
44 
45 // some stack size defines
46 #define UT_THREAD_DEFAULT_STACK_SIZE (8U*1024U*1024U)
47 #define UT_THREAD_SMALL_STACK_SIZE (1U*1024U*1024U)
48 
49 typedef void *(*UTthreadFunc)(void*);
50 
51 // forward declarations
52 class UT_TaskScope;
53 
55 {
56 public:
57  // The destructor will wait until the thread is idle before it completes
58  // If you wish to kill the thread, call killThread() first.
59  virtual ~UT_Thread();
60 
61  // This enum specifies the current state for a persistent thread. The
62  // thread will typically be running or idle. If the thread is idle, it's
63  // behaviour will be determined by the SpinState.
64  enum State
65  {
67  ThreadRunning
68  };
69 
70  // // The thread status determines how the thread will behave once the
71  // callback function is completed:
72  // ThreadSingleRun - The thread cannot be restarted
73  // ThreadLowUsage - The thread will yeild cycles while idle
74  //
75  enum SpinMode
76  {
79  };
80 
81  /// Allocate a new thread
82  /// @param spin_mode Use ThreadSingleRun to have it exit when the thread
83  /// callback is finished. Otherwise, ThreadLowUsage
84  /// will cause the thread to loop back and wait for
85  /// more startThread() calls to run different thread
86  /// callbacks in the same thread.
87  /// @param uses_tbb Leave at true unless you absolutely know that no
88  /// TBB tasks will be spawned in thread callbacks.
89  static UT_Thread *allocThread(SpinMode spin_mode, bool uses_tbb=true);
90 
91  static int getNumProcessors();
92 
93  /// This is only valid in debug builds
94  static int activeThreadCount();
95 
96  /// Reset the number of threads that is used by Houdini. This will reread
97  /// the HOUDINI_MAXTHREADS setting.
98  /// @note There should be no active tasks when this is called.
99  /// @note Only call this from the MAIN THREAD!
100  static void resetNumProcessors();
101 
102  // getMyThreadId() is inlined for speed if we're using pthreads.
103 #if defined(USE_PTHREADS)
104  static ut_thread_id_t getMyThreadId() { return pthread_self(); }
105 #else
106  static ut_thread_id_t getMyThreadId();
107 #endif
108 
109  static ut_thread_id_t getMainThreadId();
110  static int getMainSequentialThreadId();
111  static inline int isMainThread()
112  {
113  return getMyThreadId() == getMainThreadId();
114  }
115 
116  /// Returns true if the current thread is a UT_Thread.
117  /// Returns false if the current thread is either the main thread
118  /// or a TBB thread.
119  static bool isUTThreadCurrent();
120 
121  /// Returns true iff the current thread is allowed to create more tasks.
122  /// This is sometimes disabled, to avoid needing to create a UT_TaskArena
123  /// for small cases that won't get much benefit from threading.
124  /// This should be checked by anything using tbb::parallel_for,
125  /// tbb::parallel_invoke, or anything else creating TBB tasks.
126  static bool isThreadingEnabled();
127 
128  /// This is used to disable (false) threading for the current thread,
129  /// to avoid needing to create a UT_TaskArena for small cases that won't
130  /// get much benefit from threading. It returns if it was enabled before.
131  /// It is also used to re-enable (true) threading for the current thread.
132  static bool setThreadingEnabled(bool will_be_enabled);
133 
135  {
136  public:
138  : myPreviouslyEnabled(setThreadingEnabled(false))
139  {}
141  {
142  if (myPreviouslyEnabled)
143  setThreadingEnabled(true);
144  }
145  private:
146  const bool myPreviouslyEnabled;
147  };
148 
149  // CPU pauses the task for a given number of cycles
150  static inline void pause(uint cycles)
151  {
152  for(uint i = 0; i < cycles; i++)
153 #if defined(USE_PTHREADS)
154  __asm__ __volatile__("pause;");
155 #else
156  _mm_pause();
157 #endif
158  }
159  // Yields the task to the scheduler.
160 #if defined(USE_PTHREADS)
161  static inline void yield(bool higher_only=false)
162  {
163  if (higher_only)
164  {
165  ::sched_yield();
166  }
167  else
168  {
169  // Sleep for 100ns. That's 10,000,000 sleep
170  // cycles a second (in case you don't have a
171  // calculator :-)
172  struct timespec ts = {0,100};
173  ::nanosleep(&ts, 0);
174  }
175  }
176 #else
177  static void yield(bool higher_only=false);
178 #endif
179 
180  /// This function has been deprecated. Use SYS_SequentialThreadIndex::get()
181  /// or SYSgetSTID instead.
182  static int SYS_DEPRECATED(12.5) getMySequentialThreadIndex()
183  { return SYS_SequentialThreadIndex::get(); }
184 
185  /// Configure the global number of tasks used by the system
186  /// - The default value of 0 uses the number of logical cores on the system
187  /// - A negative value wraps it from the number of logical cores.
188  /// eg. -1 will use all cores except for 1.
189  /// - If the negative value exceeds the number of logical cores, it is
190  /// clamped to a value of 1.
191  /// @note Only call this in the main thread when there are no tasks active.
192  /// @note This function is NOT thread-safe.
193  static void configureMaxThreads(int maxthreads = 0);
194 
195  /// Configure the default stack size for threads
196  /// - A value of 0 uses the stack size of the main thread
197  /// - A value larger than 0 will use that specific stack size
198  /// @note Only call this in the main thread when there are no tasks active.
199  /// @note This function is NOT thread-safe.
200  static void configureThreadStackSize(int stacksize);
201 
202  /// Returns true if configureMaxThreads() has been called at least once
203  static bool isMaxThreadsConfigured();
204 
206  {
207  public:
210  };
211 
212  /// Return function pointer to terminate task scheduler that is activated
213  /// by configureMaxThreads(). This function should called prior to exit()
214  /// in order to avoid possible deadlocks when the process exits. Note that
215  /// multiple calls to the termination function are handled by only
216  /// terminating the first time. After that, no task scheduling is allowed.
217  using TerminateFunc = void (*)();
218  static TerminateFunc getTaskSchedulerExitCallback();
219 
220  // Start the thread running. If the thread is not in idle state, the
221  // thread will wait until it's in idle before starting. If the thread
222  // doesn't exist yet, it will be created.
223  virtual bool startThread(UTthreadFunc func, void *data,
224  int stacksize) = 0;
225 
226  // Use the global thread stack size set by configureMaxThreads()
227  bool startThread(UTthreadFunc func, void *data);
228 
229  // This method is called when the thread function is first entered.
230  // By default it does nothing but some sub-classes may need this.
231  virtual void threadStarted();
232 
233  // This method is called when the thread function is returned from.
234  // By default it sets the state to idle.
235  virtual void threadEnded();
236 
237 
238  // Some thread architectures have very expensive resources (i.e. sproc()
239  // threads). While these threads spin (are idle), they consume system
240  // resources. This method will let the user know whether the threads are
241  // resource hogs (so that if they spin for a long time, they could
242  // possibley be cleaned up).
243  virtual int isResourceHog() const;
244 
245  // For persistent threads (which get restarted)
246  virtual State getState();
247  virtual SpinMode getSpinMode();
248  virtual void waitForState(State desired) = 0;
249  virtual void setSpinMode(SpinMode spin_mode);
250 
251  // Terminate the thread process
252  virtual void killThread() = 0;
253 
254  // If it's possible to perform these tasks, the return code will be 1. If
255  // not, the return code will be 0. Not all
256  virtual int niceThread(int priority) = 0;
257  virtual int suspendThread() = 0;
258  virtual int restartThread() = 0;
259 
260  int isActive()
261  { return waitThread(0); }
262 
263  /// NOTE: This level doesn't own any data apart from itself.
264  virtual int64 getMemoryUsage(bool inclusive) const = 0;
265 
266 protected:
267  // System dependent internal functions.
268  // waitThread() returns 1 if the thread is still active (i.e. exists) and
269  // should return 0 if the thread doesn't exist. If waitThread detects
270  // that the thread no longer exists, it should do appropriate cleanup.
271  virtual int waitThread(int block=1) = 0;
272 
273  // Quick check to see that the thread is really active
274  virtual int isValid();
275 
276  // This method can be used to kill an idle process.
277  void killIdle();
278 
279  static void *threadWrapper(void *data);
280 
281  // Internally used to change the state safely.
282  virtual void setState(State state) = 0;
283 
284  volatile State myState;
287  void *myCBData;
288 
290  bool myUsesTBB;
291 
292  UT_Thread(SpinMode spin_mode, bool uses_tbb);
293 };
294 
295 // For debugging, the following uses a single thread (i.e. is not
296 // multi-threaded)
298 {
299 public:
300  UT_NullThread();
301  ~UT_NullThread() override;
302 
303  bool startThread(UTthreadFunc func, void *data,
304  int stacksize) override;
305  void killThread() override;
306  int waitThread(int block) override;
307  void waitForState(State) override;
308 
309  int niceThread(int priority) override;
310  int suspendThread() override;
311  int restartThread() override;
312 
313  int64 getMemoryUsage(bool inclusive) const override
314  {
315  int64 mem = inclusive ? sizeof(*this) : 0;
316  // NOTE: We don't know how much memory Windows uses,
317  // so we can't count it.
318  return mem;
319  }
320 
321 protected:
322  void setState(State state) override;
323 };
324 
325 
327 {
328 public:
329  UT_ThreadSet(int nthreads=-1, int null_thread_if_1_cpu = 0);
330  ~UT_ThreadSet();
331 
333  {
334  myFunc = func;
335  }
336  void setUserData(void *user_data_array, size_t structlen)
337  {
338  myUserData = user_data_array;
339  myUserDataInc = structlen;
340  }
341  void setUserData(void *user_data)
342  {
343  myUserData = user_data;
344  myUserDataInc = 0;
345  }
346 
347  void reuse(UT_Thread::SpinMode spin_mode);
348  void go();
349  int wait(int block=1);
350 
351  int getNumThreads() const { return myThreadCount; }
352  UT_Thread *getThread(int which);
353  UT_Thread *operator[](int which)
354  {
355  UT_ASSERT_P(which < myThreadCount);
356  return myThreads[which];
357  }
358 
359 protected:
363  void *myUserData;
365 };
366 
368 {
369 public:
371  {
372  NON_BLOCKING = 0, // Only assign thread if one is available
373  BLOCKING = 1, // Block until a thread is free.
374  DYNAMIC = 2 // If no threads are availble, create a new one.
375  };
376 
377  // similar to UT_ThreadSet, but a bit simpler. Called UT_ThreadFarm
378  // because it farms out the next available thread. You also don't need to
379  // match the number of data chunks to the number of threads.
380  // ie.
381  // farm = new UT_ThreadFarm(4);
382  // while(!done) {
383  // thread = farm->nextThread();
384  // thread->startThread(entrypoint, mydata);
385  // }
386  // farm->wait();
387 
388  UT_ThreadFarm(int nthreads=-1);
389  ~UT_ThreadFarm();
390 
391  // waits for the next available thread, (or returns null if none are
392  // available and block = 0). thread_index will contain the thread index
393  // if you pass it a non-null pointer.
394  UT_Thread *nextThread(int *thread_index =0,
395  AssignmentStyle style = BLOCKING);
396 
397  // waits until all threads are finished (or, returns 0 if not finished and
398  // block = 0).
399  int wait(int block = 1);
400 
401  // deletes threads in the thread farm. if kill=1 the threads are killed before
402  // cleanup, otherwise wait(1) is called.
403  void cleanup(int kill = 0);
404 
405  int getEntries() const { return myThreadCount; }
407  {
408  UT_ASSERT_P(index < myThreadCount);
409  return myThreads[index];
410  }
411 
412 protected:
413  void addThreads(int thread_count);
414 
417 };
418 
419 // Gradual backoff when there's thread contention.
421 {
422 public:
423  UT_ThreadBackoff() : myCycles(1) {}
424 
425  static const uint cycles_for_noop = 4;
426  static const uint cycles_for_pause = cycles_for_noop * 4;
427  static const uint cycles_for_yield_higher = cycles_for_pause * 2;
428  static const uint cycles_for_yield_all = cycles_for_yield_higher * 2;
429 
430  // Same thresholds as hboost::detail::yield(), but different behaviour
431  void wait()
432  {
433  if (myCycles > cycles_for_yield_all)
434  {
435  // Yield the thread completely, to any and all comers.
436  UT_Thread::yield(false);
437  return;
438  }
439 
440  if (myCycles <= cycles_for_noop)
441  {
442  // Noop.
443  }
444  else if (myCycles <= cycles_for_pause)
445  {
446  UT_Thread::pause(myCycles);
447  }
448  else if (myCycles <= cycles_for_yield_higher)
449  {
450  UT_Thread::yield(true);
451  }
452  myCycles += (myCycles+1)>>1;
453  }
454 
455  void reset()
456  {
457  myCycles = 1;
458  }
459 
460 private:
461  uint myCycles;
462 };
463 
464 // This function has been deprecated. Use SYSgetSTID instead.
465 static inline int SYS_DEPRECATED(12.5)
466 UTgetSTID()
467 {
469 }
470 
471 #endif
volatile State myState
Definition: UT_Thread.h:284
int getNumThreads() const
Definition: UT_Thread.h:351
void yield()
Definition: thread.h:119
void setUserData(void *user_data)
Definition: UT_Thread.h:341
#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:313
virtual int restartThread()=0
int myThreadCount
Definition: UT_Thread.h:360
GLuint index
Definition: glew.h:1814
void *(* UTthreadFunc)(void *)
Definition: UT_Thread.h:49
UTthreadFunc myCallback
Definition: UT_Thread.h:286
UT_Thread * operator[](int index)
Definition: UT_Thread.h:406
SpinMode mySpinMode
Definition: UT_Thread.h:285
void * myCBData
Definition: UT_Thread.h:287
#define UT_API
Definition: UT_API.h:13
UT_Thread * operator[](int which)
Definition: UT_Thread.h:353
int getEntries() const
Definition: UT_Thread.h:405
UT_Thread ** myThreads
Definition: UT_Thread.h:361
virtual void setState(State state)=0
*tasks wait()
GLint GLenum GLsizei GLint GLsizei const void * data
Definition: glew.h:1379
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:134
int myThreadCount
Definition: UT_Thread.h:415
virtual void waitForState(State desired)=0
void
Definition: png.h:1083
void setFunc(UTthreadFunc func)
Definition: UT_Thread.h:332
virtual bool startThread(UTthreadFunc func, void *data, int stacksize)=0
long long int64
Definition: SYS_Types.h:116
virtual void killThread()=0
int64 myUserDataInc
Definition: UT_Thread.h:364
const UT_TaskScope * myTaskScope
Definition: UT_Thread.h:289
bool myUsesTBB
Definition: UT_Thread.h:290
virtual int suspendThread()=0
virtual int niceThread(int priority)=0
static int isMainThread()
Definition: UT_Thread.h:111
GLenum func
Definition: glcorearb.h:782
UTthreadFunc myFunc
Definition: UT_Thread.h:362
UT_Thread ** myThreads
Definition: UT_Thread.h:416
static void pause(uint cycles)
Definition: UT_Thread.h:150
int isActive()
Definition: UT_Thread.h:260
static void yield(bool higher_only=false)
virtual int waitThread(int block=1)=0
void * myUserData
Definition: UT_Thread.h:363
unsigned int uint
Definition: SYS_Types.h:45
void setUserData(void *user_data_array, size_t structlen)
Definition: UT_Thread.h:336