00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00032
00034 namespace internal {
00035
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
00043 task* execute()
00044 {
00045 my_function();
00046 return NULL;
00047 }
00048 };
00049
00050
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;
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 }
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
00086 class parallel_invoke_helper : public empty_task {
00087 public:
00088
00089 class parallel_invoke_noop {
00090 public:
00091 void operator() () const {}
00092 };
00093
00094 parallel_invoke_helper(int number_of_children)
00095 {
00096 set_ref_count(number_of_children + 1);
00097 }
00098
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
00108
00109 template <typename function1, typename function2>
00110 void add_children (const function1& _func1, const function2& _func2)
00111 {
00112
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
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
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
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
00144 {}
00145
00146 ~parallel_invoke_cleaner(){
00147 root.destroy(root);
00148 }
00149 internal::parallel_invoke_helper& root;
00150 };
00151 }
00153
00157
00158
00160
00161
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
00362
00363 #endif