00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00040
00042 namespace internal {
00043
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
00051 task* execute()
00052 {
00053 my_function();
00054 return NULL;
00055 }
00056 };
00057
00058
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;
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 }
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
00094 class parallel_invoke_helper : public empty_task {
00095 public:
00096
00097 class parallel_invoke_noop {
00098 public:
00099 void operator() () const {}
00100 };
00101
00102 parallel_invoke_helper(int number_of_children)
00103 {
00104 set_ref_count(number_of_children + 1);
00105 }
00106
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
00116
00117 template <typename function1, typename function2>
00118 void add_children (const function1& _func1, const function2& _func2)
00119 {
00120
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
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
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
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
00152 {}
00153
00154 ~parallel_invoke_cleaner(){
00155 root.destroy(root);
00156 }
00157 internal::parallel_invoke_helper& root;
00158 };
00159 }
00161
00165
00166
00168
00169
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
00370
00371 #endif