2 Copyright 2005-2010 Intel Corporation. All Rights Reserved.
4 This file is part of Threading Building Blocks.
6 Threading Building Blocks is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
10 Threading Building Blocks is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Threading Building Blocks; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 As a special exception, you may use this file as part of a free software
20 library without restriction. Specifically, if other files instantiate
21 templates or use macros or inline functions from this file, or you compile
22 this file and link it with other files to produce an executable, this
23 file does not by itself cause the resulting executable to be covered by
24 the GNU General Public License. This exception does not however
25 invalidate any other reasons why the executable file might be covered by
26 the GNU General Public License.
29 #ifndef __TBB_parallel_invoke_H
30 #define __TBB_parallel_invoke_H
38 // Simple task object, executing user method
39 template<typename function>
40 class function_invoker : public task{
42 function_invoker(const function& _function) : my_function(_function) {}
44 const function &my_function;
53 // The class spawns two or three child tasks
54 template <size_t N, typename function1, typename function2, typename function3>
55 class spawner : public task {
57 const function1& my_func1;
58 const function2& my_func2;
59 const function3& my_func3;
66 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
68 recycle_as_safe_continuation();
69 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
70 __TBB_ASSERT(invoker2, "Child task allocation failed");
72 size_t n = N; // To prevent compiler warnings
74 internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
75 __TBB_ASSERT(invoker3, "Child task allocation failed");
85 spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
88 // Creates and spawns child tasks
89 class parallel_invoke_helper : public empty_task {
91 // Dummy functor class
92 class parallel_invoke_noop {
94 void operator() () const {}
96 // Creates a helper object with user-defined number of children expected
97 parallel_invoke_helper(int number_of_children)
99 set_ref_count(number_of_children + 1);
101 // Adds child task and spawns it
102 template <typename function>
103 void add_child (const function &_func)
105 internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
106 __TBB_ASSERT(invoker, "Child task allocation failed");
110 // Adds a task with multiple child tasks and spawns it
112 template <typename function1, typename function2>
113 void add_children (const function1& _func1, const function2& _func2)
115 // The third argument is dummy, it is ignored actually.
116 parallel_invoke_noop noop;
117 internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
121 template <typename function1, typename function2, typename function3>
122 void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
124 internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
128 // Waits for all child tasks
129 template <typename F0>
130 void run_and_finish(const F0& f0)
132 internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
133 __TBB_ASSERT(invoker, "Child task allocation failed");
134 spawn_and_wait_for_all(*invoker);
137 // The class destroys root if exception occured as well as in normal case
138 class parallel_invoke_cleaner: internal::no_copy {
140 parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context) : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children))
142 ~parallel_invoke_cleaner(){
145 internal::parallel_invoke_helper& root;
147 } // namespace internal
150 /** \name parallel_invoke
153 //! Executes a list of tasks in parallel and waits for all tasks to complete.
154 /** @ingroup algorithms */
156 // parallel_invoke with user-defined context
158 template<typename F0, typename F1 >
159 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
160 internal::parallel_invoke_cleaner cleaner(2, context);
161 internal::parallel_invoke_helper& root = cleaner.root;
165 root.run_and_finish(f0);
169 template<typename F0, typename F1, typename F2 >
170 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
171 internal::parallel_invoke_cleaner cleaner(3, context);
172 internal::parallel_invoke_helper& root = cleaner.root;
177 root.run_and_finish(f0);
181 template<typename F0, typename F1, typename F2, typename F3>
182 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
183 tbb::task_group_context& context)
185 internal::parallel_invoke_cleaner cleaner(4, context);
186 internal::parallel_invoke_helper& root = cleaner.root;
192 root.run_and_finish(f0);
196 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
197 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
198 tbb::task_group_context& context)
200 internal::parallel_invoke_cleaner cleaner(3, context);
201 internal::parallel_invoke_helper& root = cleaner.root;
203 root.add_children(f4, f3);
204 root.add_children(f2, f1);
206 root.run_and_finish(f0);
210 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
211 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
212 tbb::task_group_context& context)
214 internal::parallel_invoke_cleaner cleaner(3, context);
215 internal::parallel_invoke_helper& root = cleaner.root;
217 root.add_children(f5, f4, f3);
218 root.add_children(f2, f1);
220 root.run_and_finish(f0);
224 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
225 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
226 const F5& f5, const F6& f6,
227 tbb::task_group_context& context)
229 internal::parallel_invoke_cleaner cleaner(3, context);
230 internal::parallel_invoke_helper& root = cleaner.root;
232 root.add_children(f6, f5, f4);
233 root.add_children(f3, f2, f1);
235 root.run_and_finish(f0);
239 template<typename F0, typename F1, typename F2, typename F3, typename F4,
240 typename F5, typename F6, typename F7>
241 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
242 const F5& f5, const F6& f6, const F7& f7,
243 tbb::task_group_context& context)
245 internal::parallel_invoke_cleaner cleaner(4, context);
246 internal::parallel_invoke_helper& root = cleaner.root;
248 root.add_children(f7, f6, f5);
249 root.add_children(f4, f3);
250 root.add_children(f2, f1);
252 root.run_and_finish(f0);
256 template<typename F0, typename F1, typename F2, typename F3, typename F4,
257 typename F5, typename F6, typename F7, typename F8>
258 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
259 const F5& f5, const F6& f6, const F7& f7, const F8& f8,
260 tbb::task_group_context& context)
262 internal::parallel_invoke_cleaner cleaner(4, context);
263 internal::parallel_invoke_helper& root = cleaner.root;
265 root.add_children(f8, f7, f6);
266 root.add_children(f5, f4, f3);
267 root.add_children(f2, f1);
269 root.run_and_finish(f0);
273 template<typename F0, typename F1, typename F2, typename F3, typename F4,
274 typename F5, typename F6, typename F7, typename F8, typename F9>
275 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
276 const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
277 tbb::task_group_context& context)
279 internal::parallel_invoke_cleaner cleaner(4, context);
280 internal::parallel_invoke_helper& root = cleaner.root;
282 root.add_children(f9, f8, f7);
283 root.add_children(f6, f5, f4);
284 root.add_children(f3, f2, f1);
286 root.run_and_finish(f0);
290 template<typename F0, typename F1>
291 void parallel_invoke(const F0& f0, const F1& f1) {
292 task_group_context context;
293 parallel_invoke<F0, F1>(f0, f1, context);
296 template<typename F0, typename F1, typename F2>
297 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
298 task_group_context context;
299 parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
302 template<typename F0, typename F1, typename F2, typename F3 >
303 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
304 task_group_context context;
305 parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
308 template<typename F0, typename F1, typename F2, typename F3, typename F4>
309 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
310 task_group_context context;
311 parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
314 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
315 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
316 task_group_context context;
317 parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
320 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
321 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
322 const F5& f5, const F6& f6)
324 task_group_context context;
325 parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
328 template<typename F0, typename F1, typename F2, typename F3, typename F4,
329 typename F5, typename F6, typename F7>
330 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
331 const F5& f5, const F6& f6, const F7& f7)
333 task_group_context context;
334 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
337 template<typename F0, typename F1, typename F2, typename F3, typename F4,
338 typename F5, typename F6, typename F7, typename F8>
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, const F8& f8)
342 task_group_context context;
343 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
346 template<typename F0, typename F1, typename F2, typename F3, typename F4,
347 typename F5, typename F6, typename F7, typename F8, typename F9>
348 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
349 const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
351 task_group_context context;
352 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
359 #endif /* __TBB_parallel_invoke_H */