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