File indexing completed on 2025-01-18 10:12:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef __TBB_parallel_invoke_H
0018 #define __TBB_parallel_invoke_H
0019
0020 #define __TBB_parallel_invoke_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022
0023 #include "task.h"
0024 #include "tbb_profiling.h"
0025
0026 #if __TBB_VARIADIC_PARALLEL_INVOKE
0027 #include <utility> // std::forward
0028 #endif
0029
0030 namespace tbb {
0031
0032 #if !__TBB_TASK_GROUP_CONTEXT
0033
0034 struct task_group_context {
0035 task_group_context(tbb::internal::string_index){}
0036 };
0037 #endif
0038
0039
0040 namespace internal {
0041
0042 template<typename function>
0043 class function_invoker : public task{
0044 public:
0045 function_invoker(const function& _function) : my_function(_function) {}
0046 private:
0047 const function &my_function;
0048 task* execute() __TBB_override
0049 {
0050 my_function();
0051 return NULL;
0052 }
0053 };
0054
0055
0056 template <size_t N, typename function1, typename function2, typename function3>
0057 class spawner : public task {
0058 private:
0059 const function1& my_func1;
0060 const function2& my_func2;
0061 const function3& my_func3;
0062 bool is_recycled;
0063
0064 task* execute () __TBB_override {
0065 if(is_recycled){
0066 return NULL;
0067 }else{
0068 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong");
0069 set_ref_count(N);
0070 recycle_as_safe_continuation();
0071 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2);
0072 __TBB_ASSERT(invoker2, "Child task allocation failed");
0073 spawn(*invoker2);
0074 size_t n = N;
0075 if (n>2) {
0076 internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3);
0077 __TBB_ASSERT(invoker3, "Child task allocation failed");
0078 spawn(*invoker3);
0079 }
0080 my_func1();
0081 is_recycled = true;
0082 return NULL;
0083 }
0084 }
0085
0086 public:
0087 spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {}
0088 };
0089
0090
0091 class parallel_invoke_helper : public empty_task {
0092 public:
0093
0094 class parallel_invoke_noop {
0095 public:
0096 void operator() () const {}
0097 };
0098
0099 parallel_invoke_helper(int number_of_children)
0100 {
0101 set_ref_count(number_of_children + 1);
0102 }
0103
0104 #if __TBB_VARIADIC_PARALLEL_INVOKE
0105 void add_children() {}
0106 void add_children(tbb::task_group_context&) {}
0107
0108 template <typename function>
0109 void add_children(function&& _func)
0110 {
0111 internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(std::forward<function>(_func));
0112 __TBB_ASSERT(invoker, "Child task allocation failed");
0113 spawn(*invoker);
0114 }
0115
0116 template<typename function>
0117 void add_children(function&& _func, tbb::task_group_context&)
0118 {
0119 add_children(std::forward<function>(_func));
0120 }
0121
0122
0123 template <typename function1, typename function2, typename... function>
0124 void add_children(function1&& _func1, function2&& _func2, function&&... _func)
0125 {
0126
0127 parallel_invoke_noop noop;
0128 typedef internal::spawner<2, function1, function2, parallel_invoke_noop> spawner_type;
0129 spawner_type & sub_root = *new(allocate_child()) spawner_type(std::forward<function1>(_func1), std::forward<function2>(_func2), noop);
0130 spawn(sub_root);
0131 add_children(std::forward<function>(_func)...);
0132 }
0133 #else
0134
0135 template <typename function>
0136 void add_children (const function &_func)
0137 {
0138 internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func);
0139 __TBB_ASSERT(invoker, "Child task allocation failed");
0140 spawn(*invoker);
0141 }
0142
0143
0144
0145 template <typename function1, typename function2>
0146 void add_children (const function1& _func1, const function2& _func2)
0147 {
0148
0149 parallel_invoke_noop noop;
0150 internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop);
0151 spawn(sub_root);
0152 }
0153
0154 template <typename function1, typename function2, typename function3>
0155 void add_children (const function1& _func1, const function2& _func2, const function3& _func3)
0156 {
0157 internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3);
0158 spawn(sub_root);
0159 }
0160 #endif
0161
0162
0163 template <typename F0>
0164 void run_and_finish(const F0& f0)
0165 {
0166 internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0);
0167 __TBB_ASSERT(invoker, "Child task allocation failed");
0168 spawn_and_wait_for_all(*invoker);
0169 }
0170 };
0171
0172 class parallel_invoke_cleaner: internal::no_copy {
0173 public:
0174 #if __TBB_TASK_GROUP_CONTEXT
0175 parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context)
0176 : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children))
0177 #else
0178 parallel_invoke_cleaner(int number_of_children, tbb::task_group_context&)
0179 : root(*new(task::allocate_root()) internal::parallel_invoke_helper(number_of_children))
0180 #endif
0181 {}
0182
0183 ~parallel_invoke_cleaner(){
0184 root.destroy(root);
0185 }
0186 internal::parallel_invoke_helper& root;
0187 };
0188
0189 #if __TBB_VARIADIC_PARALLEL_INVOKE
0190
0191 template<typename... T> struct impl_selector;
0192
0193 template<typename T1, typename... T> struct impl_selector<T1, T...> {
0194 typedef typename impl_selector<T...>::type type;
0195 };
0196
0197 template<typename T> struct impl_selector<T> {
0198 typedef false_type type;
0199 };
0200 template<> struct impl_selector<task_group_context&> {
0201 typedef true_type type;
0202 };
0203
0204
0205 inline task_group_context& get_context( task_group_context& tgc ) { return tgc; }
0206
0207 template<typename T1, typename... T>
0208 task_group_context& get_context( T1&& , T&&... t )
0209 { return get_context( std::forward<T>(t)... ); }
0210
0211
0212 template<typename F0, typename F1, typename... F>
0213 void parallel_invoke_impl(true_type, F0&& f0, F1&& f1, F&&... f) {
0214 __TBB_STATIC_ASSERT(sizeof...(F)>0, "Variadic parallel_invoke implementation broken?");
0215
0216 const size_t number_of_children = 2 + sizeof...(F)/2;
0217 parallel_invoke_cleaner cleaner(number_of_children, get_context(std::forward<F>(f)...));
0218 parallel_invoke_helper& root = cleaner.root;
0219
0220 root.add_children(std::forward<F>(f)...);
0221 root.add_children(std::forward<F1>(f1));
0222 root.run_and_finish(std::forward<F0>(f0));
0223 }
0224
0225
0226 template<typename F0, typename F1, typename... F>
0227 void parallel_invoke_impl(false_type, F0&& f0, F1&& f1, F&&... f) {
0228 tbb::task_group_context context(PARALLEL_INVOKE);
0229
0230 parallel_invoke_impl(true_type(), std::forward<F0>(f0), std::forward<F1>(f1), std::forward<F>(f)..., context);
0231 }
0232 #endif
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242 #if __TBB_VARIADIC_PARALLEL_INVOKE
0243
0244
0245
0246 template<typename F0, typename F1, typename... F>
0247 void parallel_invoke(F0&& f0, F1&& f1, F&&... f) {
0248 typedef typename internal::impl_selector<internal::false_type, F...>::type selector_type;
0249 internal::parallel_invoke_impl(selector_type(), std::forward<F0>(f0), std::forward<F1>(f1), std::forward<F>(f)...);
0250 }
0251
0252 #else
0253
0254
0255
0256 template<typename F0, typename F1 >
0257 void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) {
0258 internal::parallel_invoke_cleaner cleaner(2, context);
0259 internal::parallel_invoke_helper& root = cleaner.root;
0260
0261 root.add_children(f1);
0262
0263 root.run_and_finish(f0);
0264 }
0265
0266
0267 template<typename F0, typename F1, typename F2 >
0268 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) {
0269 internal::parallel_invoke_cleaner cleaner(3, context);
0270 internal::parallel_invoke_helper& root = cleaner.root;
0271
0272 root.add_children(f2);
0273 root.add_children(f1);
0274
0275 root.run_and_finish(f0);
0276 }
0277
0278
0279 template<typename F0, typename F1, typename F2, typename F3>
0280 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3,
0281 tbb::task_group_context& context)
0282 {
0283 internal::parallel_invoke_cleaner cleaner(4, context);
0284 internal::parallel_invoke_helper& root = cleaner.root;
0285
0286 root.add_children(f3);
0287 root.add_children(f2);
0288 root.add_children(f1);
0289
0290 root.run_and_finish(f0);
0291 }
0292
0293
0294 template<typename F0, typename F1, typename F2, typename F3, typename F4 >
0295 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0296 tbb::task_group_context& context)
0297 {
0298 internal::parallel_invoke_cleaner cleaner(3, context);
0299 internal::parallel_invoke_helper& root = cleaner.root;
0300
0301 root.add_children(f4, f3);
0302 root.add_children(f2, f1);
0303
0304 root.run_and_finish(f0);
0305 }
0306
0307
0308 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
0309 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5,
0310 tbb::task_group_context& context)
0311 {
0312 internal::parallel_invoke_cleaner cleaner(3, context);
0313 internal::parallel_invoke_helper& root = cleaner.root;
0314
0315 root.add_children(f5, f4, f3);
0316 root.add_children(f2, f1);
0317
0318 root.run_and_finish(f0);
0319 }
0320
0321
0322 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
0323 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0324 const F5& f5, const F6& f6,
0325 tbb::task_group_context& context)
0326 {
0327 internal::parallel_invoke_cleaner cleaner(3, context);
0328 internal::parallel_invoke_helper& root = cleaner.root;
0329
0330 root.add_children(f6, f5, f4);
0331 root.add_children(f3, f2, f1);
0332
0333 root.run_and_finish(f0);
0334 }
0335
0336
0337 template<typename F0, typename F1, typename F2, typename F3, typename F4,
0338 typename F5, typename F6, typename F7>
0339 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0340 const F5& f5, const F6& f6, const F7& f7,
0341 tbb::task_group_context& context)
0342 {
0343 internal::parallel_invoke_cleaner cleaner(4, context);
0344 internal::parallel_invoke_helper& root = cleaner.root;
0345
0346 root.add_children(f7, f6, f5);
0347 root.add_children(f4, f3);
0348 root.add_children(f2, f1);
0349
0350 root.run_and_finish(f0);
0351 }
0352
0353
0354 template<typename F0, typename F1, typename F2, typename F3, typename F4,
0355 typename F5, typename F6, typename F7, typename F8>
0356 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0357 const F5& f5, const F6& f6, const F7& f7, const F8& f8,
0358 tbb::task_group_context& context)
0359 {
0360 internal::parallel_invoke_cleaner cleaner(4, context);
0361 internal::parallel_invoke_helper& root = cleaner.root;
0362
0363 root.add_children(f8, f7, f6);
0364 root.add_children(f5, f4, f3);
0365 root.add_children(f2, f1);
0366
0367 root.run_and_finish(f0);
0368 }
0369
0370
0371 template<typename F0, typename F1, typename F2, typename F3, typename F4,
0372 typename F5, typename F6, typename F7, typename F8, typename F9>
0373 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0374 const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9,
0375 tbb::task_group_context& context)
0376 {
0377 internal::parallel_invoke_cleaner cleaner(4, context);
0378 internal::parallel_invoke_helper& root = cleaner.root;
0379
0380 root.add_children(f9, f8, f7);
0381 root.add_children(f6, f5, f4);
0382 root.add_children(f3, f2, f1);
0383
0384 root.run_and_finish(f0);
0385 }
0386
0387
0388 template<typename F0, typename F1>
0389 void parallel_invoke(const F0& f0, const F1& f1) {
0390 task_group_context context(internal::PARALLEL_INVOKE);
0391 parallel_invoke<F0, F1>(f0, f1, context);
0392 }
0393
0394 template<typename F0, typename F1, typename F2>
0395 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) {
0396 task_group_context context(internal::PARALLEL_INVOKE);
0397 parallel_invoke<F0, F1, F2>(f0, f1, f2, context);
0398 }
0399
0400 template<typename F0, typename F1, typename F2, typename F3 >
0401 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) {
0402 task_group_context context(internal::PARALLEL_INVOKE);
0403 parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context);
0404 }
0405
0406 template<typename F0, typename F1, typename F2, typename F3, typename F4>
0407 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) {
0408 task_group_context context(internal::PARALLEL_INVOKE);
0409 parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context);
0410 }
0411
0412 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5>
0413 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) {
0414 task_group_context context(internal::PARALLEL_INVOKE);
0415 parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context);
0416 }
0417
0418 template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6>
0419 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0420 const F5& f5, const F6& f6)
0421 {
0422 task_group_context context(internal::PARALLEL_INVOKE);
0423 parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context);
0424 }
0425
0426 template<typename F0, typename F1, typename F2, typename F3, typename F4,
0427 typename F5, typename F6, typename F7>
0428 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0429 const F5& f5, const F6& f6, const F7& f7)
0430 {
0431 task_group_context context(internal::PARALLEL_INVOKE);
0432 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context);
0433 }
0434
0435 template<typename F0, typename F1, typename F2, typename F3, typename F4,
0436 typename F5, typename F6, typename F7, typename F8>
0437 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0438 const F5& f5, const F6& f6, const F7& f7, const F8& f8)
0439 {
0440 task_group_context context(internal::PARALLEL_INVOKE);
0441 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context);
0442 }
0443
0444 template<typename F0, typename F1, typename F2, typename F3, typename F4,
0445 typename F5, typename F6, typename F7, typename F8, typename F9>
0446 void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4,
0447 const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9)
0448 {
0449 task_group_context context(internal::PARALLEL_INVOKE);
0450 parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context);
0451 }
0452 #endif
0453
0454
0455 }
0456
0457 #include "internal/_warning_suppress_disable_notice.h"
0458 #undef __TBB_parallel_invoke_H_include_area
0459
0460 #endif