Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
parallel_invoke.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2005-2019 Intel Corporation
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 
16 
17 
18 
19 */
20 
21 #ifndef __TBB_parallel_invoke_H
22 #define __TBB_parallel_invoke_H
23 
24 #include "task.h"
25 #include "tbb_profiling.h"
26 
27 #if __TBB_VARIADIC_PARALLEL_INVOKE
28  #include <utility> // std::forward
29 #endif
30 
31 namespace tbb {
32 
33 #if !__TBB_TASK_GROUP_CONTEXT
34 
35  struct task_group_context {
37  };
38 #endif /* __TBB_TASK_GROUP_CONTEXT */
39 
41 namespace internal {
42  // Simple task object, executing user method
43  template<typename function>
44  class function_invoker : public task{
45  public:
46  function_invoker(const function& _function) : my_function(_function) {}
47  private:
48  const function &my_function;
50  {
51  my_function();
52  return NULL;
53  }
54  };
55 
56  // The class spawns two or three child tasks
57  template <size_t N, typename function1, typename function2, typename function3>
58  class spawner : public task {
59  private:
60  const function1& my_func1;
61  const function2& my_func2;
62  const function3& my_func3;
64 
66  if(is_recycled){
67  return NULL;
68  }else{
69  __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
70  set_ref_count(N);
72  internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
73  __TBB_ASSERT(invoker2, "Child task allocation failed");
74  spawn(*invoker2);
75  size_t n = N; // To prevent compiler warnings
76  if (n>2) {
77  internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
78  __TBB_ASSERT(invoker3, "Child task allocation failed");
79  spawn(*invoker3);
80  }
81  my_func1();
82  is_recycled = true;
83  return NULL;
84  }
85  } // execute
86 
87  public:
88  spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
89  };
90 
91  // Creates and spawns child tasks
93  public:
94  // Dummy functor class
96  public:
97  void operator() () const {}
98  };
99  // Creates a helper object with user-defined number of children expected
100  parallel_invoke_helper(int number_of_children)
101  {
102  set_ref_count(number_of_children + 1);
103  }
104 
105 #if __TBB_VARIADIC_PARALLEL_INVOKE
106  void add_children() {}
108 
109  template <typename function>
110  void add_children(function&& _func)
111  {
112  internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(std::forward<function>(_func));
113  __TBB_ASSERT(invoker, "Child task allocation failed");
114  spawn(*invoker);
115  }
116 
117  template<typename function>
118  void add_children(function&& _func, tbb::task_group_context&)
119  {
120  add_children(std::forward<function>(_func));
121  }
122 
123  // Adds child(ren) task(s) and spawns them
124  template <typename function1, typename function2, typename... function>
125  void add_children(function1&& _func1, function2&& _func2, function&&... _func)
126  {
127  // The third argument is dummy, it is ignored actually.
128  parallel_invoke_noop noop;
129  typedef internal::spawner<2, function1, function2, parallel_invoke_noop> spawner_type;
130  spawner_type & sub_root = *new(allocate_child()) spawner_type(std::forward<function1>(_func1), std::forward<function2>(_func2), noop);
131  spawn(sub_root);
132  add_children(std::forward<function>(_func)...);
133  }
134 #else
135  // Adds child task and spawns it
136  template <typename function>
137  void add_children (const function &_func)
138  {
139  internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
140  __TBB_ASSERT(invoker, "Child task allocation failed");
141  spawn(*invoker);
142  }
143 
144  // Adds a task with multiple child tasks and spawns it
145  // two arguments
146  template <typename function1, typename function2>
147  void add_children (const function1& _func1, const function2& _func2)
148  {
149  // The third argument is dummy, it is ignored actually.
151  internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
152  spawn(sub_root);
153  }
154  // three arguments
155  template <typename function1, typename function2, typename function3>
156  void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
157  {
158  internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
159  spawn(sub_root);
160  }
161 #endif // __TBB_VARIADIC_PARALLEL_INVOKE
162 
163  // Waits for all child tasks
164  template <typename F0>
165  void run_and_finish(const F0& f0)
166  {
167  internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
168  __TBB_ASSERT(invoker, "Child task allocation failed");
169  spawn_and_wait_for_all(*invoker);
170  }
171  };
172  // The class destroys root if exception occurred as well as in normal case
173  class parallel_invoke_cleaner: internal::no_copy {
174  public:
175 #if __TBB_TASK_GROUP_CONTEXT
176  parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context)
177  : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children))
178 #else
179  parallel_invoke_cleaner(int number_of_children, tbb::task_group_context&)
180  : root(*new(task::allocate_root()) internal::parallel_invoke_helper(number_of_children))
181 #endif /* !__TBB_TASK_GROUP_CONTEXT */
182  {}
183 
185  root.destroy(root);
186  }
187  internal::parallel_invoke_helper& root;
188  };
189 
190 #if __TBB_VARIADIC_PARALLEL_INVOKE
191 // Determine whether the last parameter in a pack is task_group_context
192  template<typename... T> struct impl_selector; // to workaround a GCC bug
193 
194  template<typename T1, typename... T> struct impl_selector<T1, T...> {
195  typedef typename impl_selector<T...>::type type;
196  };
197 
198  template<typename T> struct impl_selector<T> {
199  typedef false_type type;
200  };
201  template<> struct impl_selector<task_group_context&> {
202  typedef true_type type;
203  };
204 
205  // Select task_group_context parameter from the back of a pack
206  inline task_group_context& get_context( task_group_context& tgc ) { return tgc; }
207 
208  template<typename T1, typename... T>
209  task_group_context& get_context( T1&& /*ignored*/, T&&... t )
210  { return get_context( std::forward<T>(t)... ); }
211 
212  // task_group_context is known to be at the back of the parameter pack
213  template<typename F0, typename F1, typename... F>
214  void parallel_invoke_impl(true_type, F0&& f0, F1&& f1, F&&... f) {
215  __TBB_STATIC_ASSERT(sizeof...(F)>0, "Variadic parallel_invoke implementation broken?");
216  // # of child tasks: f0, f1, and a task for each two elements of the pack except the last
217  const size_t number_of_children = 2 + sizeof...(F)/2;
218  parallel_invoke_cleaner cleaner(number_of_children, get_context(std::forward<F>(f)...));
219  parallel_invoke_helper& root = cleaner.root;
220 
221  root.add_children(std::forward<F>(f)...);
222  root.add_children(std::forward<F1>(f1));
223  root.run_and_finish(std::forward<F0>(f0));
224  }
225 
226  // task_group_context is not in the pack, needs to be added
227  template<typename F0, typename F1, typename... F>
228  void parallel_invoke_impl(false_type, F0&& f0, F1&& f1, F&&... f) {
229  tbb::task_group_context context(PARALLEL_INVOKE);
230  // Add context to the arguments, and redirect to the other overload
231  parallel_invoke_impl(true_type(), std::forward<F0>(f0), std::forward<F1>(f1), std::forward<F>(f)..., context);
232  }
233 #endif
234 } // namespace internal
236 
240 
243 #if __TBB_VARIADIC_PARALLEL_INVOKE
244 
245 // parallel_invoke for two or more arguments via variadic templates
246 // presence of task_group_context is defined automatically
247 template<typename F0, typename F1, typename... F>
248 void parallel_invoke(F0&& f0, F1&& f1, F&&... f) {
249  typedef typename internal::impl_selector<internal::false_type, F...>::type selector_type;
250  internal::parallel_invoke_impl(selector_type(), std::forward<F0>(f0), std::forward<F1>(f1), std::forward<F>(f)...);
251 }
252 
253 #else
254 
255 // parallel_invoke with user-defined context
256 // two arguments
257 template<typename F0, typename F1 >
258 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
259  internal::parallel_invoke_cleaner cleaner(2, context);
260  internal::parallel_invoke_helper& root = cleaner.root;
261 
262  root.add_children(f1);
263 
264  root.run_and_finish(f0);
265 }
266 
267 // three arguments
268 template<typename F0, typename F1, typename F2 >
269 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
270  internal::parallel_invoke_cleaner cleaner(3, context);
271  internal::parallel_invoke_helper& root = cleaner.root;
272 
273  root.add_children(f2);
274  root.add_children(f1);
275 
276  root.run_and_finish(f0);
277 }
278 
279 // four arguments
280 template<typename F0, typename F1, typename F2, typename F3>
281 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
282  tbb::task_group_context& context)
283 {
284  internal::parallel_invoke_cleaner cleaner(4, context);
285  internal::parallel_invoke_helper& root = cleaner.root;
286 
287  root.add_children(f3);
288  root.add_children(f2);
289  root.add_children(f1);
290 
291  root.run_and_finish(f0);
292 }
293 
294 // five arguments
295 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
296 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
297  tbb::task_group_context& context)
298 {
299  internal::parallel_invoke_cleaner cleaner(3, context);
300  internal::parallel_invoke_helper& root = cleaner.root;
301 
302  root.add_children(f4, f3);
303  root.add_children(f2, f1);
304 
305  root.run_and_finish(f0);
306 }
307 
308 // six arguments
309 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
310 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
311  tbb::task_group_context& context)
312 {
313  internal::parallel_invoke_cleaner cleaner(3, context);
314  internal::parallel_invoke_helper& root = cleaner.root;
315 
316  root.add_children(f5, f4, f3);
317  root.add_children(f2, f1);
318 
319  root.run_and_finish(f0);
320 }
321 
322 // seven arguments
323 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
324 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
325  const F5& f5, const F6& f6,
326  tbb::task_group_context& context)
327 {
328  internal::parallel_invoke_cleaner cleaner(3, context);
329  internal::parallel_invoke_helper& root = cleaner.root;
330 
331  root.add_children(f6, f5, f4);
332  root.add_children(f3, f2, f1);
333 
334  root.run_and_finish(f0);
335 }
336 
337 // eight arguments
338 template<typename F0, typename F1, typename F2, typename F3, typename F4,
339  typename F5, typename F6, typename F7>
340 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
341  const F5& f5, const F6& f6, const F7& f7,
342  tbb::task_group_context& context)
343 {
344  internal::parallel_invoke_cleaner cleaner(4, context);
345  internal::parallel_invoke_helper& root = cleaner.root;
346 
347  root.add_children(f7, f6, f5);
348  root.add_children(f4, f3);
349  root.add_children(f2, f1);
350 
351  root.run_and_finish(f0);
352 }
353 
354 // nine arguments
355 template<typename F0, typename F1, typename F2, typename F3, typename F4,
356  typename F5, typename F6, typename F7, typename F8>
357 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
358  const F5& f5, const F6& f6, const F7& f7, const F8& f8,
359  tbb::task_group_context& context)
360 {
361  internal::parallel_invoke_cleaner cleaner(4, context);
362  internal::parallel_invoke_helper& root = cleaner.root;
363 
364  root.add_children(f8, f7, f6);
365  root.add_children(f5, f4, f3);
366  root.add_children(f2, f1);
367 
368  root.run_and_finish(f0);
369 }
370 
371 // ten arguments
372 template<typename F0, typename F1, typename F2, typename F3, typename F4,
373  typename F5, typename F6, typename F7, typename F8, typename F9>
374 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
375  const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
376  tbb::task_group_context& context)
377 {
378  internal::parallel_invoke_cleaner cleaner(4, context);
379  internal::parallel_invoke_helper& root = cleaner.root;
380 
381  root.add_children(f9, f8, f7);
382  root.add_children(f6, f5, f4);
383  root.add_children(f3, f2, f1);
384 
385  root.run_and_finish(f0);
386 }
387 
388 // two arguments
389 template<typename F0, typename F1>
390 void parallel_invoke(const F0& f0, const F1& f1) {
391  task_group_context context(internal::PARALLEL_INVOKE);
392  parallel_invoke<F0, F1>(f0, f1, context);
393 }
394 // three arguments
395 template<typename F0, typename F1, typename F2>
396 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
397  task_group_context context(internal::PARALLEL_INVOKE);
398  parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
399 }
400 // four arguments
401 template<typename F0, typename F1, typename F2, typename F3 >
402 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
403  task_group_context context(internal::PARALLEL_INVOKE);
404  parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
405 }
406 // five arguments
407 template<typename F0, typename F1, typename F2, typename F3, typename F4>
408 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
409  task_group_context context(internal::PARALLEL_INVOKE);
410  parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
411 }
412 // six arguments
413 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
414 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
415  task_group_context context(internal::PARALLEL_INVOKE);
416  parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
417 }
418 // seven arguments
419 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
420 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
421  const F5& f5, const F6& f6)
422 {
423  task_group_context context(internal::PARALLEL_INVOKE);
424  parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
425 }
426 // eight arguments
427 template<typename F0, typename F1, typename F2, typename F3, typename F4,
428  typename F5, typename F6, typename F7>
429 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
430  const F5& f5, const F6& f6, const F7& f7)
431 {
432  task_group_context context(internal::PARALLEL_INVOKE);
433  parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
434 }
435 // nine arguments
436 template<typename F0, typename F1, typename F2, typename F3, typename F4,
437  typename F5, typename F6, typename F7, typename F8>
438 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
439  const F5& f5, const F6& f6, const F7& f7, const F8& f8)
440 {
441  task_group_context context(internal::PARALLEL_INVOKE);
442  parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
443 }
444 // ten arguments
445 template<typename F0, typename F1, typename F2, typename F3, typename F4,
446  typename F5, typename F6, typename F7, typename F8, typename F9>
447 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
448  const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
449 {
450  task_group_context context(internal::PARALLEL_INVOKE);
451  parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
452 }
453 #endif // __TBB_VARIADIC_PARALLEL_INVOKE
454 
455 
456 } // namespace
457 
458 #endif /* __TBB_parallel_invoke_H */
task_group_context(kind_type relation_with_parent=bound, uintptr_t t=default_traits)
Default & binding constructor.
Definition: task.h:481
#define __TBB_override
Definition: tbb_stddef.h:244
internal::allocate_child_proxy & allocate_child()
Returns proxy for overloaded new that allocates a child task of *this.
Definition: task.h:654
#define __TBB_STATIC_ASSERT(condition, msg)
Definition: tbb_stddef.h:536
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
task that does nothing. Useful for synchronization.
Definition: task.h:959
Used to form groups of tasks.
Definition: task.h:335
bool_constant< true > true_type
Definition: tbb_stddef.h:472
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type type
Base class for user-defined tasks.
Definition: task.h:592
internal::parallel_invoke_helper & root
void add_children(const function &_func)
void spawn_and_wait_for_all(task &child)
Similar to spawn followed by wait_for_all, but more efficient.
Definition: task.h:773
function_invoker(const function &_function)
parallel_invoke_helper(int number_of_children)
void parallel_invoke(const F0 &f0, const F1 &f1, tbb::task_group_context &context)
Executes a list of tasks in parallel and waits for all tasks to complete.
const function2 & my_func2
const function3 & my_func3
void add_children(const function1 &_func1, const function2 &_func2, const function3 &_func3)
The graph class.
const function1 & my_func1
parallel_invoke_cleaner(int number_of_children, tbb::task_group_context &context)
task * execute() __TBB_override
Should be overridden by derived classes.
void recycle_as_safe_continuation()
Recommended to use, safe variant of recycle_as_continuation.
Definition: task.h:692
void set_ref_count(int count)
Set reference count.
Definition: task.h:734
bool_constant< false > false_type
Definition: tbb_stddef.h:473
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type size_t void ITT_FORMAT p const __itt_domain __itt_id __itt_string_handle const wchar_t size_t ITT_FORMAT lu const __itt_domain __itt_id __itt_relation __itt_id ITT_FORMAT p const wchar_t int ITT_FORMAT __itt_group_mark d int
task * execute() __TBB_override
Should be overridden by derived classes.
void add_children(const function1 &_func1, const function2 &_func2)
spawner(const function1 &_func1, const function2 &_func2, const function3 &_func3)

Copyright © 2005-2019 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.