parallel_invoke.h

00001 /*
00002     Copyright 2005-2010 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(const function& _function) : my_function(_function) {}
00035     private:
00036         const 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         const function1& my_func1;
00050         const function2& my_func2;
00051         const 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(const function1& _func1, const function2& _func2, const 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 (const 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 (const function1& _func1, const 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 (const function1& _func1, const function2& _func2, const 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(const 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(const F0& f0, const 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(const F0& f0, const F1& f1, const 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(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
00175                      tbb::task_group_context& context)
00176 {
00177     internal::parallel_invoke_cleaner cleaner(4, context);
00178     internal::parallel_invoke_helper& root = cleaner.root;
00179 
00180     root.add_child(f3);
00181     root.add_child(f2);
00182     root.add_child(f1);
00183 
00184     root.run_and_finish(f0);
00185 }
00186 
00187 // five arguments
00188 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
00189 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00190                      tbb::task_group_context& context)
00191 {
00192     internal::parallel_invoke_cleaner cleaner(3, context);
00193     internal::parallel_invoke_helper& root = cleaner.root;
00194 
00195     root.add_children(f4, f3);
00196     root.add_children(f2, f1);
00197 
00198     root.run_and_finish(f0);
00199 }
00200 
00201 // six arguments
00202 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00203 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
00204                      tbb::task_group_context& context)
00205 {
00206     internal::parallel_invoke_cleaner cleaner(3, context);
00207     internal::parallel_invoke_helper& root = cleaner.root;
00208 
00209     root.add_children(f5, f4, f3);
00210     root.add_children(f2, f1);
00211 
00212     root.run_and_finish(f0);
00213 }
00214 
00215 // seven arguments
00216 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00217 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00218                      const F5& f5, const F6& f6,
00219                      tbb::task_group_context& context)
00220 {
00221     internal::parallel_invoke_cleaner cleaner(3, context);
00222     internal::parallel_invoke_helper& root = cleaner.root;
00223 
00224     root.add_children(f6, f5, f4);
00225     root.add_children(f3, f2, f1);
00226 
00227     root.run_and_finish(f0);
00228 }
00229 
00230 // eight arguments
00231 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00232          typename F5, typename F6, typename F7>
00233 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00234                      const F5& f5, const F6& f6, const F7& f7,
00235                      tbb::task_group_context& context)
00236 {
00237     internal::parallel_invoke_cleaner cleaner(4, context);
00238     internal::parallel_invoke_helper& root = cleaner.root;
00239 
00240     root.add_children(f7, f6, f5);
00241     root.add_children(f4, f3);
00242     root.add_children(f2, f1);
00243 
00244     root.run_and_finish(f0);
00245 }
00246 
00247 // nine arguments
00248 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00249          typename F5, typename F6, typename F7, typename F8>
00250 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00251                      const F5& f5, const F6& f6, const F7& f7, const F8& f8,
00252                      tbb::task_group_context& context)
00253 {
00254     internal::parallel_invoke_cleaner cleaner(4, context);
00255     internal::parallel_invoke_helper& root = cleaner.root;
00256 
00257     root.add_children(f8, f7, f6);
00258     root.add_children(f5, f4, f3);
00259     root.add_children(f2, f1);
00260 
00261     root.run_and_finish(f0);
00262 }
00263 
00264 // ten arguments
00265 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00266          typename F5, typename F6, typename F7, typename F8, typename F9>
00267 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00268                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
00269                      tbb::task_group_context& context)
00270 {
00271     internal::parallel_invoke_cleaner cleaner(4, context);
00272     internal::parallel_invoke_helper& root = cleaner.root;
00273 
00274     root.add_children(f9, f8, f7);
00275     root.add_children(f6, f5, f4);
00276     root.add_children(f3, f2, f1);
00277 
00278     root.run_and_finish(f0);
00279 }
00280 
00281 // two arguments
00282 template<typename F0, typename F1>
00283 void parallel_invoke(const F0& f0, const F1& f1) {
00284     task_group_context context;
00285     parallel_invoke<F0, F1>(f0, f1, context);
00286 }
00287 // three arguments
00288 template<typename F0, typename F1, typename F2>
00289 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
00290     task_group_context context;
00291     parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
00292 }
00293 // four arguments
00294 template<typename F0, typename F1, typename F2, typename F3 >
00295 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
00296     task_group_context context;
00297     parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
00298 }
00299 // five arguments
00300 template<typename F0, typename F1, typename F2, typename F3, typename F4>
00301 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
00302     task_group_context context;
00303     parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
00304 }
00305 // six arguments
00306 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00307 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
00308     task_group_context context;
00309     parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
00310 }
00311 // seven arguments
00312 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00313 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00314                      const F5& f5, const F6& f6)
00315 {
00316     task_group_context context;
00317     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
00318 }
00319 // eigth arguments
00320 template<typename F0, typename F1, typename F2, typename F3, typename F4, 
00321          typename F5, typename F6, typename F7>
00322 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00323                      const F5& f5, const F6& f6, const F7& f7)
00324 {
00325     task_group_context context;
00326     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
00327 }
00328 // nine arguments
00329 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00330          typename F5, typename F6, typename F7, typename F8>
00331 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00332                      const F5& f5, const F6& f6, const F7& f7, const F8& f8)
00333 {
00334     task_group_context context;
00335     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
00336 }
00337 // ten arguments
00338 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00339          typename F5, typename F6, typename F7, typename F8, typename F9>
00340 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00341                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
00342 {
00343     task_group_context context;
00344     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
00345 }
00346 
00348 
00349 } // namespace
00350 
00351 #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.