Shadowrun: Awakened 29 September 2011 - Build 871
parallel_invoke.h
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
00003 
00004     This file is part of Threading Building Blocks.
00005 
00006     Threading Building Blocks is free software; you can redistribute it
00007     and/or modify it under the terms of the GNU General Public License
00008     version 2 as published by the Free Software Foundation.
00009 
00010     Threading Building Blocks is distributed in the hope that it will be
00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Threading Building Blocks; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 
00019     As a special exception, you may use this file as part of a free software
00020     library without restriction.  Specifically, if other files instantiate
00021     templates or use macros or inline functions from this file, or you compile
00022     this file and link it with other files to produce an executable, this
00023     file does not by itself cause the resulting executable to be covered by
00024     the GNU General Public License.  This exception does not however
00025     invalidate any other reasons why the executable file might be covered by
00026     the GNU General Public License.
00027 */
00028 
00029 #ifndef __TBB_parallel_invoke_H
00030 #define __TBB_parallel_invoke_H
00031 
00032 #include "task.h"
00033 
00034 namespace tbb {
00035 
00037 namespace internal {
00038     // Simple task object, executing user method
00039     template<typename function>
00040     class function_invoker : public task{
00041     public:
00042         function_invoker(const function& _function) : my_function(_function) {}
00043     private:
00044         const function &my_function;
00045         /*override*/
00046         task* execute()
00047         {
00048             my_function();
00049             return NULL;
00050         }
00051     };
00052 
00053     // The class spawns two or three child tasks
00054     template <size_t N, typename function1, typename function2, typename function3>
00055     class spawner : public task {
00056     private:
00057         const function1& my_func1;
00058         const function2& my_func2;
00059         const function3& my_func3;
00060         bool is_recycled;
00061 
00062         task* execute (){
00063             if(is_recycled){
00064                 return NULL;
00065             }else{
00066                 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
00067                 set_ref_count(N);
00068                 recycle_as_safe_continuation();
00069                 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
00070                 __TBB_ASSERT(invoker2, "Child task allocation failed");
00071                 spawn(*invoker2);
00072                 size_t n = N; // To prevent compiler warnings
00073                 if (n>2) {
00074                     internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
00075                     __TBB_ASSERT(invoker3, "Child task allocation failed");
00076                     spawn(*invoker3);
00077                 }
00078                 my_func1();
00079                 is_recycled = true;
00080                 return NULL;
00081             }
00082         } // execute
00083 
00084     public:
00085         spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
00086     };
00087 
00088     // Creates and spawns child tasks
00089     class parallel_invoke_helper : public empty_task {
00090     public:
00091         // Dummy functor class
00092         class parallel_invoke_noop {
00093         public:
00094             void operator() () const {}
00095         };
00096         // Creates a helper object with user-defined number of children expected
00097         parallel_invoke_helper(int number_of_children)
00098         {
00099             set_ref_count(number_of_children + 1);
00100         }
00101         // Adds child task and spawns it
00102         template <typename function>
00103         void add_child (const function &_func)
00104         {
00105             internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
00106             __TBB_ASSERT(invoker, "Child task allocation failed");
00107             spawn(*invoker);
00108         }
00109 
00110         // Adds a task with multiple child tasks and spawns it
00111         // two arguments
00112         template <typename function1, typename function2>
00113         void add_children (const function1& _func1, const function2& _func2)
00114         {
00115             // The third argument is dummy, it is ignored actually.
00116             parallel_invoke_noop noop;
00117             internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
00118             spawn(sub_root);
00119         }
00120         // three arguments
00121         template <typename function1, typename function2, typename function3>
00122         void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
00123         {
00124             internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
00125             spawn(sub_root);
00126         }
00127 
00128         // Waits for all child tasks
00129         template <typename F0>
00130         void run_and_finish(const F0& f0)
00131         {
00132             internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
00133             __TBB_ASSERT(invoker, "Child task allocation failed");
00134             spawn_and_wait_for_all(*invoker);
00135         }
00136     };
00137     // The class destroys root if exception occured as well as in normal case
00138     class parallel_invoke_cleaner: internal::no_copy { 
00139     public:
00140         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))
00141         {}
00142         ~parallel_invoke_cleaner(){
00143             root.destroy(root);
00144         }
00145         internal::parallel_invoke_helper& root;
00146     };
00147 } // namespace internal
00149 
00153 
00154 
00156 // parallel_invoke with user-defined context
00157 // two arguments
00158 template<typename F0, typename F1 >
00159 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
00160     internal::parallel_invoke_cleaner cleaner(2, context);
00161     internal::parallel_invoke_helper& root = cleaner.root;
00162 
00163     root.add_child(f1);
00164 
00165     root.run_and_finish(f0);
00166 }
00167 
00168 // three arguments
00169 template<typename F0, typename F1, typename F2 >
00170 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
00171     internal::parallel_invoke_cleaner cleaner(3, context);
00172     internal::parallel_invoke_helper& root = cleaner.root;
00173 
00174     root.add_child(f2);
00175     root.add_child(f1);
00176 
00177     root.run_and_finish(f0);
00178 }
00179 
00180 // four arguments
00181 template<typename F0, typename F1, typename F2, typename F3>
00182 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
00183                      tbb::task_group_context& context)
00184 {
00185     internal::parallel_invoke_cleaner cleaner(4, context);
00186     internal::parallel_invoke_helper& root = cleaner.root;
00187 
00188     root.add_child(f3);
00189     root.add_child(f2);
00190     root.add_child(f1);
00191 
00192     root.run_and_finish(f0);
00193 }
00194 
00195 // five arguments
00196 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
00197 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00198                      tbb::task_group_context& context)
00199 {
00200     internal::parallel_invoke_cleaner cleaner(3, context);
00201     internal::parallel_invoke_helper& root = cleaner.root;
00202 
00203     root.add_children(f4, f3);
00204     root.add_children(f2, f1);
00205 
00206     root.run_and_finish(f0);
00207 }
00208 
00209 // six arguments
00210 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00211 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
00212                      tbb::task_group_context& context)
00213 {
00214     internal::parallel_invoke_cleaner cleaner(3, context);
00215     internal::parallel_invoke_helper& root = cleaner.root;
00216 
00217     root.add_children(f5, f4, f3);
00218     root.add_children(f2, f1);
00219 
00220     root.run_and_finish(f0);
00221 }
00222 
00223 // seven arguments
00224 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00225 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00226                      const F5& f5, const F6& f6,
00227                      tbb::task_group_context& context)
00228 {
00229     internal::parallel_invoke_cleaner cleaner(3, context);
00230     internal::parallel_invoke_helper& root = cleaner.root;
00231 
00232     root.add_children(f6, f5, f4);
00233     root.add_children(f3, f2, f1);
00234 
00235     root.run_and_finish(f0);
00236 }
00237 
00238 // eight arguments
00239 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00240          typename F5, typename F6, typename F7>
00241 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00242                      const F5& f5, const F6& f6, const F7& f7,
00243                      tbb::task_group_context& context)
00244 {
00245     internal::parallel_invoke_cleaner cleaner(4, context);
00246     internal::parallel_invoke_helper& root = cleaner.root;
00247 
00248     root.add_children(f7, f6, f5);
00249     root.add_children(f4, f3);
00250     root.add_children(f2, f1);
00251 
00252     root.run_and_finish(f0);
00253 }
00254 
00255 // nine arguments
00256 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00257          typename F5, typename F6, typename F7, typename F8>
00258 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00259                      const F5& f5, const F6& f6, const F7& f7, const F8& f8,
00260                      tbb::task_group_context& context)
00261 {
00262     internal::parallel_invoke_cleaner cleaner(4, context);
00263     internal::parallel_invoke_helper& root = cleaner.root;
00264 
00265     root.add_children(f8, f7, f6);
00266     root.add_children(f5, f4, f3);
00267     root.add_children(f2, f1);
00268 
00269     root.run_and_finish(f0);
00270 }
00271 
00272 // ten arguments
00273 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00274          typename F5, typename F6, typename F7, typename F8, typename F9>
00275 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00276                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
00277                      tbb::task_group_context& context)
00278 {
00279     internal::parallel_invoke_cleaner cleaner(4, context);
00280     internal::parallel_invoke_helper& root = cleaner.root;
00281 
00282     root.add_children(f9, f8, f7);
00283     root.add_children(f6, f5, f4);
00284     root.add_children(f3, f2, f1);
00285 
00286     root.run_and_finish(f0);
00287 }
00288 
00289 // two arguments
00290 template<typename F0, typename F1>
00291 void parallel_invoke(const F0& f0, const F1& f1) {
00292     task_group_context context;
00293     parallel_invoke<F0, F1>(f0, f1, context);
00294 }
00295 // three arguments
00296 template<typename F0, typename F1, typename F2>
00297 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
00298     task_group_context context;
00299     parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
00300 }
00301 // four arguments
00302 template<typename F0, typename F1, typename F2, typename F3 >
00303 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
00304     task_group_context context;
00305     parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
00306 }
00307 // five arguments
00308 template<typename F0, typename F1, typename F2, typename F3, typename F4>
00309 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
00310     task_group_context context;
00311     parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
00312 }
00313 // six arguments
00314 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
00315 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
00316     task_group_context context;
00317     parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
00318 }
00319 // seven arguments
00320 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
00321 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00322                      const F5& f5, const F6& f6)
00323 {
00324     task_group_context context;
00325     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
00326 }
00327 // eigth arguments
00328 template<typename F0, typename F1, typename F2, typename F3, typename F4, 
00329          typename F5, typename F6, typename F7>
00330 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00331                      const F5& f5, const F6& f6, const F7& f7)
00332 {
00333     task_group_context context;
00334     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
00335 }
00336 // nine arguments
00337 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00338          typename F5, typename F6, typename F7, typename F8>
00339 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00340                      const F5& f5, const F6& f6, const F7& f7, const F8& f8)
00341 {
00342     task_group_context context;
00343     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
00344 }
00345 // ten arguments
00346 template<typename F0, typename F1, typename F2, typename F3, typename F4,
00347          typename F5, typename F6, typename F7, typename F8, typename F9>
00348 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
00349                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
00350 {
00351     task_group_context context;
00352     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
00353 }
00354 
00356 
00357 } // namespace
00358 
00359 #endif /* __TBB_parallel_invoke_H */

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net