Intel(R) Threading Building Blocks Doxygen Documentation version 4.2.3
Loading...
Searching...
No Matches
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
30namespace tbb {
31
32#if !__TBB_TASK_GROUP_CONTEXT
34 struct task_group_context {
35 task_group_context(tbb::internal::string_index){}
36 };
37#endif /* __TBB_TASK_GROUP_CONTEXT */
38
40namespace 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 {
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");
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
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
240
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
246template<typename F0, typename F1, typename... F>
247void 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
256template<typename F0, typename F1 >
257void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
258 internal::parallel_invoke_cleaner cleaner(2, context);
260
261 root.add_children(f1);
262
263 root.run_and_finish(f0);
264}
265
266// three arguments
267template<typename F0, typename F1, typename F2 >
268void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
269 internal::parallel_invoke_cleaner cleaner(3, context);
271
272 root.add_children(f2);
273 root.add_children(f1);
274
275 root.run_and_finish(f0);
276}
277
278// four arguments
279template<typename F0, typename F1, typename F2, typename F3>
280void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
282{
283 internal::parallel_invoke_cleaner cleaner(4, context);
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
294template<typename F0, typename F1, typename F2, typename F3, typename F4 >
295void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
297{
298 internal::parallel_invoke_cleaner cleaner(3, context);
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
308template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
309void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
311{
312 internal::parallel_invoke_cleaner cleaner(3, context);
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
322template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
323void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
324 const F5& f5, const F6& f6,
326{
327 internal::parallel_invoke_cleaner cleaner(3, context);
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
337template<typename F0, typename F1, typename F2, typename F3, typename F4,
338 typename F5, typename F6, typename F7>
339void 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,
342{
343 internal::parallel_invoke_cleaner cleaner(4, context);
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
354template<typename F0, typename F1, typename F2, typename F3, typename F4,
355 typename F5, typename F6, typename F7, typename F8>
356void 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,
359{
360 internal::parallel_invoke_cleaner cleaner(4, context);
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
371template<typename F0, typename F1, typename F2, typename F3, typename F4,
372 typename F5, typename F6, typename F7, typename F8, typename F9>
373void 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,
376{
377 internal::parallel_invoke_cleaner cleaner(4, context);
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
388template<typename F0, typename F1>
389void 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
394template<typename F0, typename F1, typename F2>
395void 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
400template<typename F0, typename F1, typename F2, typename F3 >
401void 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
406template<typename F0, typename F1, typename F2, typename F3, typename F4>
407void 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
412template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
413void 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
418template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
419void 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
426template<typename F0, typename F1, typename F2, typename F3, typename F4,
427 typename F5, typename F6, typename F7>
428void 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
435template<typename F0, typename F1, typename F2, typename F3, typename F4,
436 typename F5, typename F6, typename F7, typename F8>
437void 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
444template<typename F0, typename F1, typename F2, typename F3, typename F4,
445 typename F5, typename F6, typename F7, typename F8, typename F9>
446void 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
454
455} // namespace
456
458#undef __TBB_parallel_invoke_H_include_area
459
460#endif /* __TBB_parallel_invoke_H */
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition tbb_stddef.h:165
#define __TBB_override
Definition tbb_stddef.h:240
#define __TBB_STATIC_ASSERT(condition, msg)
Definition tbb_stddef.h:553
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
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.
bool_constant< false > false_type
Definition tbb_stddef.h:490
bool_constant< true > true_type
Definition tbb_stddef.h:489
task * execute() __TBB_override
Should be overridden by derived classes.
function_invoker(const function &_function)
const function2 & my_func2
const function1 & my_func1
const function3 & my_func3
task * execute() __TBB_override
Should be overridden by derived classes.
spawner(const function1 &_func1, const function2 &_func2, const function3 &_func3)
void add_children(const function1 &_func1, const function2 &_func2)
void add_children(const function &_func)
void add_children(const function1 &_func1, const function2 &_func2, const function3 &_func3)
parallel_invoke_helper(int number_of_children)
parallel_invoke_cleaner(int number_of_children, tbb::task_group_context &context)
internal::parallel_invoke_helper & root
Used to form groups of tasks.
Definition task.h:358
Base class for user-defined tasks.
Definition task.h:615
internal::allocate_child_proxy & allocate_child()
Returns proxy for overloaded new that allocates a child task of *this.
Definition task.h:681
void spawn_and_wait_for_all(task &child)
Similar to spawn followed by wait_for_all, but more efficient.
Definition task.h:800
void recycle_as_safe_continuation()
Recommended to use, safe variant of recycle_as_continuation.
Definition task.h:719
void set_ref_count(int count)
Set reference count.
Definition task.h:761
task that does nothing. Useful for synchronization.
Definition task.h:1042
Base class for types that should not be copied or assigned.
Definition tbb_stddef.h:330

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.