2 Copyright 2005-2011 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
36 #if !__TBB_TASK_GROUP_CONTEXT
37 /** Dummy to avoid cluttering the bulk of the header with enormous amount of ifdefs. **/
38 struct task_group_context {};
39 #endif /* __TBB_TASK_GROUP_CONTEXT */
43 // Simple task object, executing user method
44 template<typename function>
45 class function_invoker : public task{
47 function_invoker(const function& _function) : my_function(_function) {}
49 const function &my_function;
58 // The class spawns two or three child tasks
59 template <size_t N, typename function1, typename function2, typename function3>
60 class spawner : public task {
62 const function1& my_func1;
63 const function2& my_func2;
64 const function3& my_func3;
71 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
73 recycle_as_safe_continuation();
74 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
75 __TBB_ASSERT(invoker2, "Child task allocation failed");
77 size_t n = N; // To prevent compiler warnings
79 internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
80 __TBB_ASSERT(invoker3, "Child task allocation failed");
90 spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
93 // Creates and spawns child tasks
94 class parallel_invoke_helper : public empty_task {
96 // Dummy functor class
97 class parallel_invoke_noop {
99 void operator() () const {}
101 // Creates a helper object with user-defined number of children expected
102 parallel_invoke_helper(int number_of_children)
104 set_ref_count(number_of_children + 1);
106 // Adds child task and spawns it
107 template <typename function>
108 void add_child (const function &_func)
110 internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
111 __TBB_ASSERT(invoker, "Child task allocation failed");
115 // Adds a task with multiple child tasks and spawns it
117 template <typename function1, typename function2>
118 void add_children (const function1& _func1, const function2& _func2)
120 // The third argument is dummy, it is ignored actually.
121 parallel_invoke_noop noop;
122 internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
126 template <typename function1, typename function2, typename function3>
127 void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
129 internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
133 // Waits for all child tasks
134 template <typename F0>
135 void run_and_finish(const F0& f0)
137 internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
138 __TBB_ASSERT(invoker, "Child task allocation failed");
139 spawn_and_wait_for_all(*invoker);
142 // The class destroys root if exception occured as well as in normal case
143 class parallel_invoke_cleaner: internal::no_copy {
145 #if __TBB_TASK_GROUP_CONTEXT
146 parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context)
147 : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children))
149 parallel_invoke_cleaner(int number_of_children, tbb::task_group_context&)
150 : root(*new(task::allocate_root()) internal::parallel_invoke_helper(number_of_children))
151 #endif /* !__TBB_TASK_GROUP_CONTEXT */
154 ~parallel_invoke_cleaner(){
157 internal::parallel_invoke_helper& root;
159 } // namespace internal
162 /** \name parallel_invoke
165 //! Executes a list of tasks in parallel and waits for all tasks to complete.
166 /** @ingroup algorithms */
168 // parallel_invoke with user-defined context
170 template<typename F0, typename F1 >
171 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
172 internal::parallel_invoke_cleaner cleaner(2, context);
173 internal::parallel_invoke_helper& root = cleaner.root;
177 root.run_and_finish(f0);
181 template<typename F0, typename F1, typename F2 >
182 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
183 internal::parallel_invoke_cleaner cleaner(3, context);
184 internal::parallel_invoke_helper& root = cleaner.root;
189 root.run_and_finish(f0);
193 template<typename F0, typename F1, typename F2, typename F3>
194 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
195 tbb::task_group_context& context)
197 internal::parallel_invoke_cleaner cleaner(4, context);
198 internal::parallel_invoke_helper& root = cleaner.root;
204 root.run_and_finish(f0);
208 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
209 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
210 tbb::task_group_context& context)
212 internal::parallel_invoke_cleaner cleaner(3, context);
213 internal::parallel_invoke_helper& root = cleaner.root;
215 root.add_children(f4, f3);
216 root.add_children(f2, f1);
218 root.run_and_finish(f0);
222 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
223 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
224 tbb::task_group_context& context)
226 internal::parallel_invoke_cleaner cleaner(3, context);
227 internal::parallel_invoke_helper& root = cleaner.root;
229 root.add_children(f5, f4, f3);
230 root.add_children(f2, f1);
232 root.run_and_finish(f0);
236 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
237 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
238 const F5& f5, const F6& f6,
239 tbb::task_group_context& context)
241 internal::parallel_invoke_cleaner cleaner(3, context);
242 internal::parallel_invoke_helper& root = cleaner.root;
244 root.add_children(f6, f5, f4);
245 root.add_children(f3, f2, f1);
247 root.run_and_finish(f0);
251 template<typename F0, typename F1, typename F2, typename F3, typename F4,
252 typename F5, typename F6, typename F7>
253 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
254 const F5& f5, const F6& f6, const F7& f7,
255 tbb::task_group_context& context)
257 internal::parallel_invoke_cleaner cleaner(4, context);
258 internal::parallel_invoke_helper& root = cleaner.root;
260 root.add_children(f7, f6, f5);
261 root.add_children(f4, f3);
262 root.add_children(f2, f1);
264 root.run_and_finish(f0);
268 template<typename F0, typename F1, typename F2, typename F3, typename F4,
269 typename F5, typename F6, typename F7, typename F8>
270 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
271 const F5& f5, const F6& f6, const F7& f7, const F8& f8,
272 tbb::task_group_context& context)
274 internal::parallel_invoke_cleaner cleaner(4, context);
275 internal::parallel_invoke_helper& root = cleaner.root;
277 root.add_children(f8, f7, f6);
278 root.add_children(f5, f4, f3);
279 root.add_children(f2, f1);
281 root.run_and_finish(f0);
285 template<typename F0, typename F1, typename F2, typename F3, typename F4,
286 typename F5, typename F6, typename F7, typename F8, typename F9>
287 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
288 const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
289 tbb::task_group_context& context)
291 internal::parallel_invoke_cleaner cleaner(4, context);
292 internal::parallel_invoke_helper& root = cleaner.root;
294 root.add_children(f9, f8, f7);
295 root.add_children(f6, f5, f4);
296 root.add_children(f3, f2, f1);
298 root.run_and_finish(f0);
302 template<typename F0, typename F1>
303 void parallel_invoke(const F0& f0, const F1& f1) {
304 task_group_context context;
305 parallel_invoke<F0, F1>(f0, f1, context);
308 template<typename F0, typename F1, typename F2>
309 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
310 task_group_context context;
311 parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
314 template<typename F0, typename F1, typename F2, typename F3 >
315 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
316 task_group_context context;
317 parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
320 template<typename F0, typename F1, typename F2, typename F3, typename F4>
321 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
322 task_group_context context;
323 parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
326 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
327 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
328 task_group_context context;
329 parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
332 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
333 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
334 const F5& f5, const F6& f6)
336 task_group_context context;
337 parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
340 template<typename F0, typename F1, typename F2, typename F3, typename F4,
341 typename F5, typename F6, typename F7>
342 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
343 const F5& f5, const F6& f6, const F7& f7)
345 task_group_context context;
346 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
349 template<typename F0, typename F1, typename F2, typename F3, typename F4,
350 typename F5, typename F6, typename F7, typename F8>
351 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
352 const F5& f5, const F6& f6, const F7& f7, const F8& f8)
354 task_group_context context;
355 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
358 template<typename F0, typename F1, typename F2, typename F3, typename F4,
359 typename F5, typename F6, typename F7, typename F8, typename F9>
360 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
361 const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
363 task_group_context context;
364 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
371 #endif /* __TBB_parallel_invoke_H */