parallel_invoke.h

00001 /*
00002     Copyright 2005-2009 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 
00029 namespace internal {
00030     // Simple task object, executing user method
00031     template<typename function>
00032     class function_invoker : public task{
00033     public:
00034         function_invoker(function& _function) : my_function(_function) {}
00035     private:
00036         function &my_function;
00037         /*override*/
00038         task* execute()
00039         {
00040             my_function();
00041             return NULL;
00042         }
00043     };
00044 
00045     // The class spawns two or three child tasks
00046     template <size_t N, typename function1, typename function2, typename function3>
00047     class spawner : public task {
00048     private:
00049         function1& my_func1;
00050         function2& my_func2;
00051         function3& my_func3;
00052         bool is_recycled;
00053 
00054         task* execute (){
00055             if(is_recycled){
00056                 return NULL;
00057             }else{
00058                 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
00059                 set_ref_count(N);
00060                 recycle_as_safe_continuation();
00061                 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
00062                 __TBB_ASSERT(invoker2, "Child task allocation failed");
00063                 spawn(*invoker2);
00064                 size_t n = N; // To prevent compiler warnings
00065                 if (n>2) {
00066                     internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
00067                     __TBB_ASSERT(invoker3, "Child task allocation failed");
00068                     spawn(*invoker3);
00069                 }
00070                 my_func1();
00071                 is_recycled = true;
00072                 return NULL;
00073             }
00074         } // execute
00075 
00076     public:
00077         spawner(function1& _func1, function2& _func2, function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
00078     };
00079 
00080     // Creates and spawns child tasks
00081     class parallel_invoke_helper : public empty_task {
00082     public:
00083         // Dummy functor class
00084         class parallel_invoke_noop {
00085         public:
00086             void operator() () const {}
00087         };
00088         // Creates a helper object with user-defined number of children expected
00089         parallel_invoke_helper(int number_of_children)
00090         {
00091             set_ref_count(number_of_children + 1);
00092         }
00093         // Adds child task and spawns it
00094         template <typename function>
00095         void add_child (function &_func)
00096         {
00097             internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
00098             __TBB_ASSERT(invoker, "Child task allocation failed");
00099             spawn(*invoker);
00100         }
00101 
00102         // Adds a task with multiple child tasks and spawns it
00103         // two arguments
00104         template <typename function1, typename function2>
00105         void add_children (function1& _func1, function2& _func2)
00106         {
00107             // The third argument is dummy, it is ignored actually.
00108             parallel_invoke_noop noop;
00109             internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
00110             spawn(sub_root);
00111         }
00112         // three arguments
00113         template <typename function1, typename function2, typename function3>
00114         void add_children (function1& _func1, function2& _func2, function3& _func3)
00115         {
00116             internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
00117             spawn(sub_root);
00118         }
00119 
00120         // Waits for all child tasks
00121         template <typename F0>
00122         void run_and_finish(F0& f0)
00123         {
00124             internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
00125             __TBB_ASSERT(invoker, "Child task allocation failed");
00126             spawn_and_wait_for_all(*invoker);
00127         }
00128     };
00129     // The class destroys root if exception occured as well as in normal case
00130     class parallel_invoke_cleaner: internal::no_copy { 
00131     public:
00132         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))
00133         {}
00134         ~parallel_invoke_cleaner(){
00135             root.destroy(root);
00136         }
00137         internal::parallel_invoke_helper& root;
00138     };
00139 } // namespace internal
00141 
00145 
00146 
00148 // parallel_invoke with user-defined context
00149 // two arguments
00150 template<typename F0, typename F1 >
00151 void parallel_invoke(F0 f0, F1 f1, tbb::task_group_context& context) {
00152     internal::parallel_invoke_cleaner cleaner(2, context);
00153     internal::parallel_invoke_helper& root = cleaner.root;
00154 
00155     root.add_child(f1);
00156 
00157     root.run_and_finish(f0);
00158 }
00159 
00160 // three arguments
00161 template<typename F0, typename F1, typename F2 >
00162 void parallel_invoke(F0 f0, F1 f1, F2 f2, tbb::task_group_context& context) {
00163     internal::parallel_invoke_cleaner cleaner(3, context);
00164     internal::parallel_invoke_helper& root = cleaner.root;
00165 
00166     root.add_child(f2);
00167     root.add_child(f1);
00168 
00169     root.run_and_finish(f0);
00170 }
00171 
00172 // four arguments
00173 template<typename F0, typename F1, typename F2, typename F3>
00174 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, tbb::task_group_context& context) {
00175     internal::parallel_invoke_cleaner cleaner(4, context);
00176     internal::parallel_invoke_helper& root = cleaner.root;
00177 
00178     root.add_child(f3);
00179     root.add_child(f2);
00180     root.add_child(f1);
00181 
00182     root.run_and_finish(f0);
00183 }
00184 
00185 // five arguments
00186 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
00187 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, tbb::task_group_context& context) {
00188     internal::parallel_invoke_cleaner cleaner(3, context);
00189     internal::parallel_invoke_helper& root = cleaner.root;
00190 
00191     root.add_children(f4, f3);
00192     root.add_children(f2, f1);
00193 
00194     root.run_and_finish(f0);
00195 }
00196 
00197 // six arguments
00198 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5 >
00199 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, tbb::task_group_context& context) {
00200     internal::parallel_invoke_cleaner cleaner(3, context);
00201     internal::parallel_invoke_helper& root = cleaner.root;
00202 
00203     root.add_children(f5, f4, f3);
00204     root.add_children(f2, f1);
00205 
00206     root.run_and_finish(f0);
00207 }
00208 
00209 // seven arguments
00210 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6 >
00211 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, tbb::task_group_context& context) {
00212     internal::parallel_invoke_cleaner cleaner(3, context);
00213     internal::parallel_invoke_helper& root = cleaner.root;
00214 
00215     root.add_children(f6, f5, f4);
00216     root.add_children(f3, f2, f1);
00217 
00218     root.run_and_finish(f0);
00219 }
00220 
00221 // eight arguments
00222 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6,
00223     typename F7>
00224 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, tbb::task_group_context& context) {
00225     internal::parallel_invoke_cleaner cleaner(4, context);
00226     internal::parallel_invoke_helper& root = cleaner.root;
00227 
00228     root.add_children(f7, f6, f5);
00229     root.add_children(f4, f3);
00230     root.add_children(f2, f1);
00231 
00232     root.run_and_finish(f0);
00233 }
00234 
00235 // nine arguments
00236 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6,
00237         typename F7, typename F8>
00238 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, F8 f8, tbb::task_group_context& context) {
00239     internal::parallel_invoke_cleaner cleaner(4, context);
00240     internal::parallel_invoke_helper& root = cleaner.root;
00241 
00242     root.add_children(f8, f7, f6);
00243     root.add_children(f5, f4, f3);
00244     root.add_children(f2, f1);
00245 
00246     root.run_and_finish(f0);
00247 }
00248 
00249 // ten arguments
00250 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6,
00251         typename F7, typename F8, typename F9>
00252 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, F8 f8, F9 f9, tbb::task_group_context& context) {
00253     internal::parallel_invoke_cleaner cleaner(4, context);
00254     internal::parallel_invoke_helper& root = cleaner.root;
00255 
00256     root.add_children(f9, f8, f7);
00257     root.add_children(f6, f5, f4);
00258     root.add_children(f3, f2, f1);
00259 
00260     root.run_and_finish(f0);
00261 }
00262 
00263 // two arguments
00264 template<typename F0, typename F1>
00265 void parallel_invoke(F0 f0, F1 f1) {
00266     task_group_context context;
00267     parallel_invoke<F0, F1>(f0, f1, context);
00268 }
00269 // three arguments
00270 template<typename F0, typename F1, typename F2>
00271 void parallel_invoke(F0 f0, F1 f1, F2 f2) {
00272     task_group_context context;
00273     parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
00274 }
00275 // four arguments
00276 template<typename F0, typename F1, typename F2, typename F3 >
00277 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3) {
00278     task_group_context context;
00279     parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
00280 }
00281 // five arguments
00282 template<typename F0, typename F1, typename F2, typename F3, typename F4>
00283 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4) {
00284     task_group_context context;
00285     parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
00286 }
00287 // six arguments
00288 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00289 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5) {
00290     task_group_context context;
00291     parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
00292 }
00293 // seven arguments
00294 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00295 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6) {
00296     task_group_context context;
00297     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
00298 }
00299 // eigth arguments
00300 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6,
00301         typename F7>
00302 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7) {
00303     task_group_context context;
00304     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
00305 }
00306 // nine arguments
00307 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6,
00308         typename F7, typename F8>
00309 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, F8 f8) {
00310     task_group_context context;
00311     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
00312 }
00313 // ten arguments
00314 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6,
00315         typename F7, typename F8, typename F9>
00316 void parallel_invoke(F0 f0, F1 f1, F2 f2, F3 f3, F4 f4, F5 f5, F6 f6, F7 f7, F8 f8, F9 f9) {
00317     task_group_context context;
00318     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
00319 }
00320 
00322 
00323 } // namespace
00324 
00325 #endif /* __TBB_parallel_invoke_H */

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