Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:58

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
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     /** Dummy to avoid cluttering the bulk of the header with enormous amount of ifdefs. **/
0034     struct task_group_context {
0035         task_group_context(tbb::internal::string_index){}
0036     };
0037 #endif /* __TBB_TASK_GROUP_CONTEXT */
0038 
0039 //! @cond INTERNAL
0040 namespace internal {
0041     // Simple task object, executing user method
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     // The class spawns two or three child tasks
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; // To prevent compiler warnings
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         } // execute
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     // Creates and spawns child tasks
0091     class parallel_invoke_helper : public empty_task {
0092     public:
0093         // Dummy functor class
0094         class parallel_invoke_noop {
0095         public:
0096             void operator() () const {}
0097         };
0098         // Creates a helper object with user-defined number of children expected
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         // Adds child(ren) task(s) and spawns them
0123         template <typename function1, typename function2, typename... function>
0124         void add_children(function1&& _func1, function2&& _func2, function&&... _func)
0125         {
0126             // The third argument is dummy, it is ignored actually.
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         // Adds child task and spawns it
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         // Adds a task with multiple child tasks and spawns it
0144         // two arguments
0145         template <typename function1, typename function2>
0146         void add_children (const function1& _func1, const function2& _func2)
0147         {
0148             // The third argument is dummy, it is ignored actually.
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         // three arguments
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 // __TBB_VARIADIC_PARALLEL_INVOKE
0161 
0162         // Waits for all child tasks
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     // The class destroys root if exception occurred as well as in normal case
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 /* !__TBB_TASK_GROUP_CONTEXT */
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 //  Determine whether the last parameter in a pack is task_group_context
0191     template<typename... T> struct impl_selector; // to workaround a GCC bug
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     // Select task_group_context parameter from the back of a pack
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&& /*ignored*/, T&&... t )
0209     { return get_context( std::forward<T>(t)... ); }
0210 
0211     // task_group_context is known to be at the back of the parameter pack
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         // # of child tasks: f0, f1, and a task for each two elements of the pack except the last
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     // task_group_context is not in the pack, needs to be added
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         // Add context to the arguments, and redirect to the other overload
0230         parallel_invoke_impl(true_type(), std::forward<F0>(f0), std::forward<F1>(f1), std::forward<F>(f)..., context);
0231     }
0232 #endif
0233 } // namespace internal
0234 //! @endcond
0235 
0236 /** \name parallel_invoke
0237     **/
0238 //@{
0239 //! Executes a list of tasks in parallel and waits for all tasks to complete.
0240 /** @ingroup algorithms */
0241 
0242 #if __TBB_VARIADIC_PARALLEL_INVOKE
0243 
0244 // parallel_invoke for two or more arguments via variadic templates
0245 // presence of task_group_context is defined automatically
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 // parallel_invoke with user-defined context
0255 // two arguments
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 // three arguments
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 // four arguments
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 // five arguments
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 // six arguments
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 // seven arguments
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 // eight arguments
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 // nine arguments
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 // ten arguments
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 // two arguments
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 // three arguments
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 // four arguments
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 // five arguments
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 // six arguments
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 // seven arguments
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 // eight arguments
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 // nine arguments
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 // ten arguments
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 // __TBB_VARIADIC_PARALLEL_INVOKE
0453 //@}
0454 
0455 } // namespace
0456 
0457 #include "internal/_warning_suppress_disable_notice.h"
0458 #undef __TBB_parallel_invoke_H_include_area
0459 
0460 #endif /* __TBB_parallel_invoke_H */