HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_ThreadedAlgorithm.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_ThreadedAlgorithm.h ( SIM Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_ThreadedAlgorithm__
12 #define __UT_ThreadedAlgorithm__
13 
14 #include "UT_API.h"
15 #include "UT_Functor.h"
16 #include "UT_Lock.h"
17 
18 #include <SYS/SYS_AtomicInt.h>
19 #include <SYS/SYS_Compiler.h>
20 #include <SYS/SYS_Types.h>
21 
22 
23 class UT_JobInfo;
24 
25 
26 ///
27 /// UT_ThreadedAlgorithm takes care of all the thread administration that a
28 /// threaded algorithm requires.
29 ///
30 /// NOTE: UT_ParallelUtil is the modern preferred method of multithreading
31 /// and should usually be used for new code.
32 ///
33 /// Its features are:
34 /// 1) it executes work in the main thread as well
35 /// 2) it assumes that the work can be divided into N parts and sends off
36 /// exactly N calls to threadfunc() (jobs). (N depends on the # of
37 /// installed processors and the maxthreads parm).
38 ///
39 /// Your callback function is called with several
40 /// useful parameters:
41 ///
42 /// void * data - the userdata pointer you provide to run()
43 /// int jobindex - there are N jobs, this is which job you're running
44 /// (0 to N-1).
45 /// int maxindex - the total number of jobs farmed (N)
46 /// UT_Lock &lock - a lock that you can use to lock other jobs out while
47 /// you work on something non-threadsafe. Accepts NULL.
48 ///
49 /// If your machine is a single proc, this will work exactly as a call to
50 /// threadfunc().
51 ///
52 /// In addition to the traditional threadfunc() callback, you can pass
53 /// in a UT_Functor1 which takes a UT_JobInfo parameter to specify the
54 /// job to be performed (see below). In this case, you may be better off
55 /// with the THREADED_METHOD macros detailed later.
56 ///
58 {
59 public:
60  UT_ThreadedAlgorithm(int maxthreads = -1);
62 
64  UT_ThreadedAlgorithm &operator=(const UT_ThreadedAlgorithm &) = delete;
65 
66  /// Starts the jobs, and waits until all are finished. This can be called
67  /// multiple times. The optional lock parm allows you to use your own
68  /// lock; if not specified, this class's lock will be used.
69  void run(void (*threadfunc)(void *, int, int, UT_Lock &),
70  void *userdata,
71  UT_Lock *lock = 0);
72 
73  /// Starts the jobs and waits until all are finished.
74  /// Since this uses a functor, you are expected to use BindFirst
75  /// to hide any user data you may have
76  /// While a return type is specified, it is not used. This is because
77  /// compiler bugs prohibit a Functor2 that returns null.
78  void run(UT_Functor1<int, const UT_JobInfo &> functor,
79  UT_Lock *lock = 0);
80 
81 private:
82  UT_Lock *myLock;
83  int myThreadCount;
84  bool myIsRoot;
85  static SYS_AtomicInt32 ourThreadedAlgorithmInUse;
86 };
87 
88 ///
89 /// Defines the work required for each invocation of *Partial
90 /// to complete.
91 ///
93 {
94 public:
95  UT_JobInfo(int jobidx, int numjobs, UT_Lock *lock, SYS_AtomicInt32 *aint = 0)
96  {
97  myJob = jobidx;
98  myNumJobs = numjobs;
99  myLock = lock;
100  myTask = aint;
101  myLocalTask = 0;
102  }
103 
104  /// The number of jobs is the total number of threads
105  /// that is running and job() is your thread #, starting at 0
106  /// and going up to numJobs()-1
107  int job() const { return myJob; }
108  int numJobs() const { return myNumJobs; }
109 
110  /// These control a shared AtomicInt32 so you can split
111  /// tasks among jobs using load balancing. The total number
112  /// is in this case up to you to detect.
113  /// The JobIds will start with 0 and each call will get a unique
114  /// higher number.
115  /// Example:
116  /// for (i = info.nextTask(); i < maxtask; i = info.nextTask())
117  int32 nextTask() const;
118 
119  /// Resets the task list. You are responsible for creating
120  /// a barrier to ensure that all the other threads have
121  /// hit the end of the tasks!
122  /// This is *not* required for your first loop as you will
123  /// already start at task 0.
124  void resetTasks() const;
125 
126  /// Given "units" work, report which units you are responsible
127  /// for with this JobInfo. The resulting interval is [start, end),
128  /// Appropriate for loop:
129  /// for (info.divideWork(total, i, end); i < end; i++)
130  void divideWork(int units, int &start, int &end) const;
131  void divideWork(exint units, exint &start, exint &end) const;
132 
133  /// lock and unlock a lock shared by all the jobs. This lock
134  /// is special cased to a no-op in the threadless case to avoid
135  /// overhead.
136  void lock() const
137  {
138  if (myLock)
139  myLock->lock();
140  }
141  void unlock() const
142  {
143  if (myLock)
144  myLock->unlock();
145  }
146 
147 protected:
148  int myJob, myNumJobs;
151  mutable int myLocalTask;
152 };
153 
155 {
156 public:
158  : myLock(lock)
159  { lock.lock(); }
160 
161  ~UT_AutoJobInfoLock() { myLock.unlock(); }
162 
163 private:
164  const UT_JobInfo &myLock;
165 };
166 
167 ///
168 /// @file
169 /// This macro is equivalent to
170 /// @code
171 /// for (i = 0; i < n; i++)
172 /// @endcode
173 ///
174 /// It will, however break it into BLOCK sized chunks for each thread,
175 /// allowing for load balancing
176 /// NB: Because it relies on the info.nextTask() starting at zero, you
177 /// can only loop once in this manner.
178 /// NB: This is a double loop, so break; does not work as you expect.
179 /// NB: The iterator, i, does not have to be defined.
180 /// An example of use:
181 ///
182 /// @code
183 /// FOR_INFOTASKS(info, i, n, 100)
184 /// {
185 /// // Process task i.
186 /// }
187 /// @endcode
188 ///
189 /// If you want opInterrupt() triggered for every block completed,
190 ///
191 /// @code
192 /// FOR_INFOTASKS_BOSS(info, i, n, 100, boss)
193 /// {
194 /// // Process task i.
195 /// }
196 /// @endcode
197 ///
198 #define FOR_INFOTASKS(info, i, n, blocksize) \
199 for (int task = info.nextTask() * blocksize; task < n; task = info.nextTask() * blocksize) \
200  for (int i = task, lcl_final = SYSmin(task+blocksize, (int)n); i < lcl_final; i++)
201 
202 #define FOR_INFOTASKS_BOSS(info, i, n, blocksize, boss) \
203 for (int task = info.nextTask() * blocksize; task < n && !boss->opInterrupt(); task = info.nextTask() * blocksize) \
204  for (int i = task, lcl_final = SYSmin(task+blocksize, (int)n); i < lcl_final; i++)
205 
206 
207 ///
208 /// @file
209 /// These macros automatically create all the wrapper functions
210 /// required to set up a multithreaded function call that can
211 /// be invoked transparently.
212 ///
213 /// An example of use:
214 /// @code
215 /// class Foobar
216 /// {
217 /// ...
218 /// THREADED_METHOD2(Foobar, positions.entries() > 100,
219 /// translate,
220 /// UT_Vector3Array &, positions,
221 /// const UT_Vector3 &, delta)
222 ///
223 /// void translatePartial(UT_Vector3Array &positions, const UT_Vector3 &delta,
224 /// const UT_JobInfo &info);
225 /// ...
226 /// }
227 ///
228 /// void
229 /// Foobar::translatePartial(UT_Vector3Array &positions, const UT_Vector3 &delta,
230 /// const UT_JobInfo &info)
231 /// {
232 /// int i, n;
233 ///
234 /// for (info.divideWork(positions.entries(), i, n); i < n; i++)
235 /// {
236 /// positions(i) += delta;
237 /// }
238 /// }
239 /// @endcode
240 ///
241 /// The suffix number is the number of parameters the function
242 /// should take - THREADED_METHOD#(). The parameters to the macro are:
243 ///
244 /// @code
245 /// THREADED_METHOD#(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, ...);
246 /// @endcode
247 ///
248 /// The DOMULTI is a boolean value (which may be a function returning
249 /// such) which determines if multithreading should be performed.
250 /// This lets you disable the multithreading for small batches.
251 /// Note it executes inside of METHOD, so has access to the parameters
252 /// in the CLASS. For threaded methods with parameters, you need to
253 /// specify both the PARMTYPE and the PARMNAME for each parameter.
254 ///
255 /// The user must both prototype & implement a
256 /// @code
257 /// void functionPartial(parameterlist, const &UT_JobInfo)
258 /// @endcode
259 /// which does all the real work (see above).
260 ///
261 /// Automatically created by the THREADED_METHOD macro are:
262 /// @code
263 /// void function(parameterlist) <- what users can invoke
264 /// void functionNoThread(parameterlist) <- unthreaded version
265 /// int functionInvokeParital(...) <- marshalling function.
266 /// @endcode
267 ///
268 
269 #define THREADED_METHOD_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD) \
270 void METHOD ## NoThread() ISCONST \
271 { \
272  METHOD ## Partial(UT_JobInfo(0, 1, 0)); \
273 } \
274 \
275 void METHOD() ISCONST \
276 { \
277  if (!(DOMULTI)) \
278  { \
279  METHOD ## NoThread(); \
280  return; \
281  } \
282  \
283  auto functor = [&](const UT_JobInfo &info) \
284  { METHOD ## Partial(info); return 0; }; \
285  UT_ThreadedAlgorithm alg; \
286  alg.run(functor); \
287 } \
288 /**/
289 
290 #define THREADED_METHOD1_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1) \
291 void METHOD ## NoThread(PARMTYPE1 PARMNAME1) ISCONST \
292 { \
293  METHOD ## Partial(PARMNAME1, UT_JobInfo(0, 1, 0)); \
294 } \
295 \
296 void METHOD(PARMTYPE1 PARMNAME1) ISCONST \
297 { \
298  if (!(DOMULTI)) \
299  { \
300  METHOD ## NoThread(PARMNAME1); \
301  return; \
302  } \
303  \
304  auto functor = [&](const UT_JobInfo &info) \
305  { METHOD ## Partial(PARMNAME1, info); return 0; }; \
306  UT_ThreadedAlgorithm alg; \
307  alg.run(functor); \
308 } \
309 /**/
310 
311 #define THREADED_METHOD2_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2) \
312 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2) ISCONST \
313 { \
314  METHOD ## Partial(PARMNAME1, PARMNAME2, UT_JobInfo(0, 1, 0)); \
315 } \
316 \
317 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2) ISCONST \
318 { \
319  if (!(DOMULTI)) \
320  { \
321  METHOD ## NoThread(PARMNAME1, PARMNAME2); \
322  return; \
323  } \
324  \
325  auto functor = [&](const UT_JobInfo &info) \
326  { METHOD ## Partial(PARMNAME1, PARMNAME2, info); return 0; }; \
327  UT_ThreadedAlgorithm alg; \
328  alg.run(functor); \
329 } \
330 /**/
331 
332 #define THREADED_METHOD3_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3) \
333 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3) ISCONST \
334 { \
335  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, UT_JobInfo(0, 1, 0)); \
336 } \
337 \
338 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3) ISCONST \
339 { \
340  if (!(DOMULTI)) \
341  { \
342  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3); \
343  return; \
344  } \
345  \
346  auto functor = [&](const UT_JobInfo &info) \
347  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, info); return 0; }; \
348  UT_ThreadedAlgorithm alg; \
349  alg.run(functor); \
350 } \
351 /**/
352 
353 #define THREADED_METHOD4_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4) \
354 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4) ISCONST \
355 { \
356  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, UT_JobInfo(0, 1, 0)); \
357 } \
358 \
359 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4) ISCONST \
360 { \
361  if (!(DOMULTI)) \
362  { \
363  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4); \
364  return; \
365  } \
366  \
367  auto functor = [&](const UT_JobInfo &info) \
368  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, info); return 0; }; \
369  UT_ThreadedAlgorithm alg; \
370  alg.run(functor); \
371 } \
372 /**/
373 
374 #define THREADED_METHOD5_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5) \
375 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5) ISCONST \
376 { \
377  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, UT_JobInfo(0, 1, 0)); \
378 } \
379 \
380 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5) ISCONST \
381 { \
382  if (!(DOMULTI)) \
383  { \
384  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5); \
385  return; \
386  } \
387  \
388  auto functor = [&](const UT_JobInfo &info) \
389  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, info); return 0; }; \
390  UT_ThreadedAlgorithm alg; \
391  alg.run(functor); \
392 } \
393 /**/
394 
395 #define THREADED_METHOD6_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6) \
396 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6) ISCONST \
397 { \
398  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, UT_JobInfo(0, 1, 0)); \
399 } \
400 \
401 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6) ISCONST \
402 { \
403  if (!(DOMULTI)) \
404  { \
405  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6); \
406  return; \
407  } \
408  \
409  auto functor = [&](const UT_JobInfo &info) \
410  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, info); return 0; }; \
411  UT_ThreadedAlgorithm alg; \
412  alg.run(functor); \
413 } \
414 /**/
415 
416 #define THREADED_METHOD7_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7) \
417 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7) ISCONST \
418 { \
419  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, UT_JobInfo(0, 1, 0)); \
420 } \
421 \
422 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7) ISCONST \
423 { \
424  if (!(DOMULTI)) \
425  { \
426  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7); \
427  return; \
428  } \
429  \
430  auto functor = [&](const UT_JobInfo &info) \
431  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, info); return 0; }; \
432  UT_ThreadedAlgorithm alg; \
433  alg.run(functor); \
434 } \
435 /**/
436 
437 #define THREADED_METHOD8_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8) \
438 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7, PARMTYPE8 PARMNAME8) ISCONST \
439 { \
440  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, UT_JobInfo(0, 1, 0)); \
441 } \
442 \
443 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7, PARMTYPE8 PARMNAME8) ISCONST \
444 { \
445  if (!(DOMULTI)) \
446  { \
447  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8); \
448  return; \
449  } \
450  \
451  auto functor = [&](const UT_JobInfo &info) \
452  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, info); return 0; }; \
453  UT_ThreadedAlgorithm alg; \
454  alg.run(functor); \
455 } \
456 /**/
457 
458 #define THREADED_METHOD9_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9) \
459 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7, PARMTYPE8 PARMNAME8, PARMTYPE9 PARMNAME9) ISCONST \
460 { \
461  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, PARMNAME9, UT_JobInfo(0, 1, 0)); \
462 } \
463 \
464 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7, PARMTYPE8 PARMNAME8, PARMTYPE9 PARMNAME9) ISCONST \
465 { \
466  if (!(DOMULTI)) \
467  { \
468  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, PARMNAME9); \
469  return; \
470  } \
471  \
472  auto functor = [&](const UT_JobInfo &info) \
473  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, PARMNAME9, info); return 0; }; \
474  UT_ThreadedAlgorithm alg; \
475  alg.run(functor); \
476 } \
477 /**/
478 
479 #define THREADED_METHOD10_INTERNAL(ISCONST, CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9, PARMTYPE10, PARMNAME10) \
480 void METHOD ## NoThread(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7, PARMTYPE8 PARMNAME8, PARMTYPE9 PARMNAME9, PARMTYPE10 PARMNAME10) ISCONST \
481 { \
482  METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, PARMNAME9, PARMNAME10, UT_JobInfo(0, 1, 0)); \
483 } \
484 \
485 void METHOD(PARMTYPE1 PARMNAME1, PARMTYPE2 PARMNAME2, PARMTYPE3 PARMNAME3, PARMTYPE4 PARMNAME4, PARMTYPE5 PARMNAME5, PARMTYPE6 PARMNAME6, PARMTYPE7 PARMNAME7, PARMTYPE8 PARMNAME8, PARMTYPE9 PARMNAME9, PARMTYPE10 PARMNAME10) ISCONST \
486 { \
487  if (!(DOMULTI)) \
488  { \
489  METHOD ## NoThread(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, PARMNAME9, PARMNAME10); \
490  return; \
491  } \
492  \
493  auto functor = [&](const UT_JobInfo &info) \
494  { METHOD ## Partial(PARMNAME1, PARMNAME2, PARMNAME3, PARMNAME4, PARMNAME5, PARMNAME6, PARMNAME7, PARMNAME8, PARMNAME9, PARMNAME10, info); return 0; }; \
495  UT_ThreadedAlgorithm alg; \
496  alg.run(functor); \
497 } \
498 /**/
499 
500 #define THREADED_METHOD(CLASSNAME, DOMULTI, METHOD) \
501  THREADED_METHOD_INTERNAL( , CLASSNAME, DOMULTI, METHOD)
502 #define THREADED_METHOD_CONST(CLASSNAME, DOMULTI, METHOD) \
503  THREADED_METHOD_INTERNAL(const , CLASSNAME, DOMULTI, METHOD)
504 
505 #define THREADED_METHOD1(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1) \
506  THREADED_METHOD1_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1)
507 #define THREADED_METHOD1_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1) \
508  THREADED_METHOD1_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1)
509 
510 #define THREADED_METHOD2(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2) \
511  THREADED_METHOD2_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2)
512 #define THREADED_METHOD2_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2) \
513  THREADED_METHOD2_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2)
514 
515 #define THREADED_METHOD3(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3) \
516  THREADED_METHOD3_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3)
517 #define THREADED_METHOD3_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3) \
518  THREADED_METHOD3_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3)
519 
520 #define THREADED_METHOD4(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4) \
521  THREADED_METHOD4_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4)
522 #define THREADED_METHOD4_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4) \
523  THREADED_METHOD4_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4)
524 
525 #define THREADED_METHOD5(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5) \
526  THREADED_METHOD5_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5)
527 #define THREADED_METHOD5_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5) \
528  THREADED_METHOD5_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5)
529 
530 #define THREADED_METHOD6(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6) \
531  THREADED_METHOD6_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6)
532 #define THREADED_METHOD6_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6) \
533  THREADED_METHOD6_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6)
534 
535 #define THREADED_METHOD7(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7) \
536  THREADED_METHOD7_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7)
537 #define THREADED_METHOD7_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7) \
538  THREADED_METHOD7_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7)
539 
540 #define THREADED_METHOD8(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8) \
541  THREADED_METHOD8_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8)
542 #define THREADED_METHOD8_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8) \
543  THREADED_METHOD8_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8)
544 
545 #define THREADED_METHOD9(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9) \
546  THREADED_METHOD9_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9)
547 #define THREADED_METHOD9_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9) \
548  THREADED_METHOD9_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9)
549 
550 #define THREADED_METHOD10(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9, PARMTYPE10, PARMNAME10) \
551  THREADED_METHOD10_INTERNAL( , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9, PARMTYPE10, PARMNAME10)
552 #define THREADED_METHOD10_CONST(CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9, PARMTYPE10, PARMNAME10) \
553  THREADED_METHOD10_INTERNAL(const , CLASSNAME, DOMULTI, METHOD, PARMTYPE1, PARMNAME1, PARMTYPE2, PARMNAME2, PARMTYPE3, PARMNAME3, PARMTYPE4, PARMNAME4, PARMTYPE5, PARMNAME5, PARMTYPE6, PARMNAME6, PARMTYPE7, PARMNAME7, PARMTYPE8, PARMNAME8, PARMTYPE9, PARMNAME9, PARMTYPE10, PARMNAME10)
554 
555 #endif
int int32
Definition: SYS_Types.h:39
UT_JobInfo(int jobidx, int numjobs, UT_Lock *lock, SYS_AtomicInt32 *aint=0)
GLuint start
Definition: glcorearb.h:475
int64 exint
Definition: SYS_Types.h:125
#define UT_API
Definition: UT_API.h:14
UT_AutoJobInfoLock(const UT_JobInfo &lock)
GLuint GLuint end
Definition: glcorearb.h:475
#define SYS_NO_DISCARD_RESULT
Definition: SYS_Compiler.h:93
void lock() const
GLfloat units
Definition: glcorearb.h:408
int numJobs() const
void unlock() const
SYS_AtomicInt32 * myTask
int job() const