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

- File List
- File Members

# parallel_invoke.h

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

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