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

Copyright © 2005-2020 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.