parallel_invoke.h Source File

- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# 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.