parallel_invoke.h

00001 /*
00002     Copyright 2005-2011 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
00019 */
00020 
00021 #ifndef __TBB_parallel_invoke_H
00022 #define __TBB_parallel_invoke_H
00023 
00024 #include "task.h"
00025 
00026 namespace tbb {
00027 
00028 #if !__TBB_TASK_GROUP_CONTEXT
00029 
00030     struct task_group_context {};
00031 #endif /* __TBB_TASK_GROUP_CONTEXT */
00032 
00034 namespace internal {
00035     // Simple task object, executing user method
00036     template<typename function>
00037     class function_invoker : public task{
00038     public:
00039         function_invoker(const function& _function) : my_function(_function) {}
00040     private:
00041         const function &my_function;
00042         /*override*/
00043         task* execute()
00044         {
00045             my_function();
00046             return NULL;
00047         }
00048     };
00049 
00050     // The class spawns two or three child tasks
00051     template <size_t N, typename function1, typename function2, typename function3>
00052     class spawner : public task {
00053     private:
00054         const function1& my_func1;
00055         const function2& my_func2;
00056         const function3& my_func3;
00057         bool is_recycled;
00058 
00059         task* execute (){
00060             if(is_recycled){
00061                 return NULL;
00062             }else{
00063                 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
00064                 set_ref_count(N);
00065                 recycle_as_safe_continuation();
00066                 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
00067                 __TBB_ASSERT(invoker2, "Child task allocation failed");
00068                 spawn(*invoker2);
00069                 size_t n = N; // To prevent compiler warnings
00070                 if (n>2) {
00071                     internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
00072                     __TBB_ASSERT(invoker3, "Child task allocation failed");
00073                     spawn(*invoker3);
00074                 }
00075                 my_func1();
00076                 is_recycled = true;
00077                 return NULL;
00078             }
00079         } // execute
00080 
00081     public:
00082         spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
00083     };
00084 
00085     // Creates and spawns child tasks
00086     class parallel_invoke_helper : public empty_task {
00087     public:
00088         // Dummy functor class
00089         class parallel_invoke_noop {
00090         public:
00091             void operator() () const {}
00092         };
00093         // Creates a helper object with user-defined number of children expected
00094         parallel_invoke_helper(int number_of_children)
00095         {
00096             set_ref_count(number_of_children + 1);
00097         }
00098         // Adds child task and spawns it
00099         template <typename function>
00100         void add_child (const function &_func)
00101         {
00102             internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
00103             __TBB_ASSERT(invoker, "Child task allocation failed");
00104             spawn(*invoker);
00105         }
00106 
00107         // Adds a task with multiple child tasks and spawns it
00108         // two arguments
00109         template <typename function1, typename function2>
00110         void add_children (const function1& _func1, const function2& _func2)
00111         {
00112             // The third argument is dummy, it is ignored actually.
00113             parallel_invoke_noop noop;
00114             internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
00115             spawn(sub_root);
00116         }
00117         // three arguments
00118         template <typename function1, typename function2, typename function3>
00119         void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
00120         {
00121             internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
00122             spawn(sub_root);
00123         }
00124 
00125         // Waits for all child tasks
00126         template <typename F0>
00127         void run_and_finish(const F0& f0)
00128         {
00129             internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
00130             __TBB_ASSERT(invoker, "Child task allocation failed");
00131             spawn_and_wait_for_all(*invoker);
00132         }
00133     };
00134     // The class destroys root if exception occured as well as in normal case
00135     class parallel_invoke_cleaner: internal::no_copy { 
00136     public:
00137 #if __TBB_TASK_GROUP_CONTEXT
00138         parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context)
00139             : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children))
00140 #else
00141         parallel_invoke_cleaner(int number_of_children, tbb::task_group_context&)
00142             : root(*new(task::allocate_root()) internal::parallel_invoke_helper(number_of_children))
00143 #endif /* !__TBB_TASK_GROUP_CONTEXT */
00144         {}
00145 
00146         ~parallel_invoke_cleaner(){
00147             root.destroy(root);
00148         }
00149         internal::parallel_invoke_helper& root;
00150     };
00151 } // namespace internal
00153 
00157 
00158 
00160 // parallel_invoke with user-defined context
00161 // two arguments
00162 template<typename F0, typename F1 >
00163 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
00164     internal::parallel_invoke_cleaner cleaner(2, context);
00165     internal::parallel_invoke_helper& root = cleaner.root;
00166 
00167     root.add_child(f1);
00168 
00169     root.run_and_finish(f0);
00170 }
00171 
00172 // three arguments
00173 template<typename F0, typename F1, typename F2 >
00174 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
00175     internal::parallel_invoke_cleaner cleaner(3, context);
00176     internal::parallel_invoke_helper& root = cleaner.root;
00177 
00178     root.add_child(f2);
00179     root.add_child(f1);
00180 
00181     root.run_and_finish(f0);
00182 }
00183 
00184 // four arguments
00185 template<typename F0, typename F1, typename F2, typename F3>
00186 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
00187                      tbb::task_group_context& context)
00188 {
00189     internal::parallel_invoke_cleaner cleaner(4, context);
00190     internal::parallel_invoke_helper& root = cleaner.root;
00191 
00192     root.add_child(f3);
00193     root.add_child(f2);
00194     root.add_child(f1);
00195 
00196     root.run_and_finish(f0);
00197 }
00198 
00199 // five arguments
00200 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
00201 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00202                      tbb::task_group_context& context)
00203 {
00204     internal::parallel_invoke_cleaner cleaner(3, context);
00205     internal::parallel_invoke_helper& root = cleaner.root;
00206 
00207     root.add_children(f4, f3);
00208     root.add_children(f2, f1);
00209 
00210     root.run_and_finish(f0);
00211 }
00212 
00213 // six arguments
00214 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00215 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
00216                      tbb::task_group_context& context)
00217 {
00218     internal::parallel_invoke_cleaner cleaner(3, context);
00219     internal::parallel_invoke_helper& root = cleaner.root;
00220 
00221     root.add_children(f5, f4, f3);
00222     root.add_children(f2, f1);
00223 
00224     root.run_and_finish(f0);
00225 }
00226 
00227 // seven arguments
00228 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00229 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00230                      const F5& f5, const F6& f6,
00231                      tbb::task_group_context& context)
00232 {
00233     internal::parallel_invoke_cleaner cleaner(3, context);
00234     internal::parallel_invoke_helper& root = cleaner.root;
00235 
00236     root.add_children(f6, f5, f4);
00237     root.add_children(f3, f2, f1);
00238 
00239     root.run_and_finish(f0);
00240 }
00241 
00242 // eight arguments
00243 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00244          typename F5, typename F6, typename F7>
00245 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00246                      const F5& f5, const F6& f6, const F7& f7,
00247                      tbb::task_group_context& context)
00248 {
00249     internal::parallel_invoke_cleaner cleaner(4, context);
00250     internal::parallel_invoke_helper& root = cleaner.root;
00251 
00252     root.add_children(f7, f6, f5);
00253     root.add_children(f4, f3);
00254     root.add_children(f2, f1);
00255 
00256     root.run_and_finish(f0);
00257 }
00258 
00259 // nine arguments
00260 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00261          typename F5, typename F6, typename F7, typename F8>
00262 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00263                      const F5& f5, const F6& f6, const F7& f7, const F8& f8,
00264                      tbb::task_group_context& context)
00265 {
00266     internal::parallel_invoke_cleaner cleaner(4, context);
00267     internal::parallel_invoke_helper& root = cleaner.root;
00268 
00269     root.add_children(f8, f7, f6);
00270     root.add_children(f5, f4, f3);
00271     root.add_children(f2, f1);
00272 
00273     root.run_and_finish(f0);
00274 }
00275 
00276 // ten arguments
00277 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00278          typename F5, typename F6, typename F7, typename F8, typename F9>
00279 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00280                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
00281                      tbb::task_group_context& context)
00282 {
00283     internal::parallel_invoke_cleaner cleaner(4, context);
00284     internal::parallel_invoke_helper& root = cleaner.root;
00285 
00286     root.add_children(f9, f8, f7);
00287     root.add_children(f6, f5, f4);
00288     root.add_children(f3, f2, f1);
00289 
00290     root.run_and_finish(f0);
00291 }
00292 
00293 // two arguments
00294 template<typename F0, typename F1>
00295 void parallel_invoke(const F0& f0, const F1& f1) {
00296     task_group_context context;
00297     parallel_invoke<F0, F1>(f0, f1, context);
00298 }
00299 // three arguments
00300 template<typename F0, typename F1, typename F2>
00301 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
00302     task_group_context context;
00303     parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
00304 }
00305 // four arguments
00306 template<typename F0, typename F1, typename F2, typename F3 >
00307 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
00308     task_group_context context;
00309     parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
00310 }
00311 // five arguments
00312 template<typename F0, typename F1, typename F2, typename F3, typename F4>
00313 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
00314     task_group_context context;
00315     parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
00316 }
00317 // six arguments
00318 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00319 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
00320     task_group_context context;
00321     parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
00322 }
00323 // seven arguments
00324 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00325 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00326                      const F5& f5, const F6& f6)
00327 {
00328     task_group_context context;
00329     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
00330 }
00331 // eigth arguments
00332 template<typename F0, typename F1, typename F2, typename F3, typename F4, 
00333          typename F5, typename F6, typename F7>
00334 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00335                      const F5& f5, const F6& f6, const F7& f7)
00336 {
00337     task_group_context context;
00338     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
00339 }
00340 // nine arguments
00341 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00342          typename F5, typename F6, typename F7, typename F8>
00343 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00344                      const F5& f5, const F6& f6, const F7& f7, const F8& f8)
00345 {
00346     task_group_context context;
00347     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
00348 }
00349 // ten arguments
00350 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00351          typename F5, typename F6, typename F7, typename F8, typename F9>
00352 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00353                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
00354 {
00355     task_group_context context;
00356     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
00357 }
00358 
00360 
00361 } // namespace
00362 
00363 #endif /* __TBB_parallel_invoke_H */

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