]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/parallel_invoke.h
02c3e80ef1b70019a8eb0392957bea7ff7c85bc6
[casparcg] / tbb30_20100406oss / include / tbb / parallel_invoke.h
1 /*
2     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
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.
9
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.
14
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
18
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.
27 */
28
29 #ifndef __TBB_parallel_invoke_H
30 #define __TBB_parallel_invoke_H
31
32 #include "task.h"
33
34 namespace tbb {
35
36 //! @cond INTERNAL
37 namespace internal {
38     // Simple task object, executing user method
39     template<typename function>
40     class function_invoker : public task{
41     public:
42         function_invoker(const function& _function) : my_function(_function) {}
43     private:
44         const function &my_function;
45         /*override*/
46         task* execute()
47         {
48             my_function();
49             return NULL;
50         }
51     };
52
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 {
56     private:
57         const function1& my_func1;
58         const function2& my_func2;
59         const function3& my_func3;
60         bool is_recycled;
61
62         task* execute (){
63             if(is_recycled){
64                 return NULL;
65             }else{
66                 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
67                 set_ref_count(N);
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");
71                 spawn(*invoker2);
72                 size_t n = N; // To prevent compiler warnings
73                 if (n>2) {
74                     internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
75                     __TBB_ASSERT(invoker3, "Child task allocation failed");
76                     spawn(*invoker3);
77                 }
78                 my_func1();
79                 is_recycled = true;
80                 return NULL;
81             }
82         } // execute
83
84     public:
85         spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
86     };
87
88     // Creates and spawns child tasks
89     class parallel_invoke_helper : public empty_task {
90     public:
91         // Dummy functor class
92         class parallel_invoke_noop {
93         public:
94             void operator() () const {}
95         };
96         // Creates a helper object with user-defined number of children expected
97         parallel_invoke_helper(int number_of_children)
98         {
99             set_ref_count(number_of_children + 1);
100         }
101         // Adds child task and spawns it
102         template <typename function>
103         void add_child (const function &_func)
104         {
105             internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
106             __TBB_ASSERT(invoker, "Child task allocation failed");
107             spawn(*invoker);
108         }
109
110         // Adds a task with multiple child tasks and spawns it
111         // two arguments
112         template <typename function1, typename function2>
113         void add_children (const function1& _func1, const function2& _func2)
114         {
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);
118             spawn(sub_root);
119         }
120         // three arguments
121         template <typename function1, typename function2, typename function3>
122         void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
123         {
124             internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
125             spawn(sub_root);
126         }
127
128         // Waits for all child tasks
129         template <typename F0>
130         void run_and_finish(const F0& f0)
131         {
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);
135         }
136     };
137     // The class destroys root if exception occured as well as in normal case
138     class parallel_invoke_cleaner: internal::no_copy { 
139     public:
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))
141         {}
142         ~parallel_invoke_cleaner(){
143             root.destroy(root);
144         }
145         internal::parallel_invoke_helper& root;
146     };
147 } // namespace internal
148 //! @endcond
149
150 /** \name parallel_invoke
151     **/
152 //@{
153 //! Executes a list of tasks in parallel and waits for all tasks to complete.
154 /** @ingroup algorithms */
155
156 // parallel_invoke with user-defined context
157 // two arguments
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;
162
163     root.add_child(f1);
164
165     root.run_and_finish(f0);
166 }
167
168 // three arguments
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;
173
174     root.add_child(f2);
175     root.add_child(f1);
176
177     root.run_and_finish(f0);
178 }
179
180 // four arguments
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)
184 {
185     internal::parallel_invoke_cleaner cleaner(4, context);
186     internal::parallel_invoke_helper& root = cleaner.root;
187
188     root.add_child(f3);
189     root.add_child(f2);
190     root.add_child(f1);
191
192     root.run_and_finish(f0);
193 }
194
195 // five arguments
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)
199 {
200     internal::parallel_invoke_cleaner cleaner(3, context);
201     internal::parallel_invoke_helper& root = cleaner.root;
202
203     root.add_children(f4, f3);
204     root.add_children(f2, f1);
205
206     root.run_and_finish(f0);
207 }
208
209 // six arguments
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)
213 {
214     internal::parallel_invoke_cleaner cleaner(3, context);
215     internal::parallel_invoke_helper& root = cleaner.root;
216
217     root.add_children(f5, f4, f3);
218     root.add_children(f2, f1);
219
220     root.run_and_finish(f0);
221 }
222
223 // seven arguments
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)
228 {
229     internal::parallel_invoke_cleaner cleaner(3, context);
230     internal::parallel_invoke_helper& root = cleaner.root;
231
232     root.add_children(f6, f5, f4);
233     root.add_children(f3, f2, f1);
234
235     root.run_and_finish(f0);
236 }
237
238 // eight arguments
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)
244 {
245     internal::parallel_invoke_cleaner cleaner(4, context);
246     internal::parallel_invoke_helper& root = cleaner.root;
247
248     root.add_children(f7, f6, f5);
249     root.add_children(f4, f3);
250     root.add_children(f2, f1);
251
252     root.run_and_finish(f0);
253 }
254
255 // nine arguments
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)
261 {
262     internal::parallel_invoke_cleaner cleaner(4, context);
263     internal::parallel_invoke_helper& root = cleaner.root;
264
265     root.add_children(f8, f7, f6);
266     root.add_children(f5, f4, f3);
267     root.add_children(f2, f1);
268
269     root.run_and_finish(f0);
270 }
271
272 // ten arguments
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)
278 {
279     internal::parallel_invoke_cleaner cleaner(4, context);
280     internal::parallel_invoke_helper& root = cleaner.root;
281
282     root.add_children(f9, f8, f7);
283     root.add_children(f6, f5, f4);
284     root.add_children(f3, f2, f1);
285
286     root.run_and_finish(f0);
287 }
288
289 // two arguments
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);
294 }
295 // three arguments
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);
300 }
301 // four arguments
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);
306 }
307 // five arguments
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);
312 }
313 // six arguments
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);
318 }
319 // seven arguments
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)
323 {
324     task_group_context context;
325     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
326 }
327 // eigth arguments
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)
332 {
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);
335 }
336 // nine arguments
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)
341 {
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);
344 }
345 // ten arguments
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)
350 {
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);
353 }
354
355 //@}
356
357 } // namespace
358
359 #endif /* __TBB_parallel_invoke_H */