You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							371 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							371 lines
						
					
					
						
							14 KiB
						
					
					
				| /* | |
|     Copyright 2005-2014 Intel Corporation.  All Rights Reserved. | |
|  | |
|     This file is part of Threading Building Blocks. | |
|  | |
|     Threading Building Blocks is free software; you can redistribute it | |
|     and/or modify it under the terms of the GNU General Public License | |
|     version 2 as published by the Free Software Foundation. | |
|  | |
|     Threading Building Blocks is distributed in the hope that it will be | |
|     useful, but WITHOUT ANY WARRANTY; without even the implied warranty | |
|     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|     GNU General Public License for more details. | |
|  | |
|     You should have received a copy of the GNU General Public License | |
|     along with Threading Building Blocks; if not, write to the Free Software | |
|     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | |
|  | |
|     As a special exception, you may use this file as part of a free software | |
|     library without restriction.  Specifically, if other files instantiate | |
|     templates or use macros or inline functions from this file, or you compile | |
|     this file and link it with other files to produce an executable, this | |
|     file does not by itself cause the resulting executable to be covered by | |
|     the GNU General Public License.  This exception does not however | |
|     invalidate any other reasons why the executable file might be covered by | |
|     the GNU General Public License. | |
| */ | |
| 
 | |
| #ifndef __TBB_parallel_invoke_H | |
| #define __TBB_parallel_invoke_H | |
|  | |
| #include "task.h" | |
|  | |
| namespace tbb { | |
| 
 | |
| #if !__TBB_TASK_GROUP_CONTEXT | |
|     /** Dummy to avoid cluttering the bulk of the header with enormous amount of ifdefs. **/ | |
|     struct task_group_context {}; | |
| #endif /* __TBB_TASK_GROUP_CONTEXT */ | |
|  | |
| //! @cond INTERNAL | |
| namespace internal { | |
|     // Simple task object, executing user method | |
|     template<typename function> | |
|     class function_invoker : public task{ | |
|     public: | |
|         function_invoker(const function& _function) : my_function(_function) {} | |
|     private: | |
|         const function &my_function; | |
|         /*override*/ | |
|         task* execute() | |
|         { | |
|             my_function(); | |
|             return NULL; | |
|         } | |
|     }; | |
| 
 | |
|     // The class spawns two or three child tasks | |
|     template <size_t N, typename function1, typename function2, typename function3> | |
|     class spawner : public task { | |
|     private: | |
|         const function1& my_func1; | |
|         const function2& my_func2; | |
|         const function3& my_func3; | |
|         bool is_recycled; | |
| 
 | |
|         task* execute (){ | |
|             if(is_recycled){ | |
|                 return NULL; | |
|             }else{ | |
|                 __TBB_ASSERT(N==2 || N==3, "Number of arguments passed to spawner is wrong"); | |
|                 set_ref_count(N); | |
|                 recycle_as_safe_continuation(); | |
|                 internal::function_invoker<function2>* invoker2 = new (allocate_child()) internal::function_invoker<function2>(my_func2); | |
|                 __TBB_ASSERT(invoker2, "Child task allocation failed"); | |
|                 spawn(*invoker2); | |
|                 size_t n = N; // To prevent compiler warnings | |
|                 if (n>2) { | |
|                     internal::function_invoker<function3>* invoker3 = new (allocate_child()) internal::function_invoker<function3>(my_func3); | |
|                     __TBB_ASSERT(invoker3, "Child task allocation failed"); | |
|                     spawn(*invoker3); | |
|                 } | |
|                 my_func1(); | |
|                 is_recycled = true; | |
|                 return NULL; | |
|             } | |
|         } // execute | |
|  | |
|     public: | |
|         spawner(const function1& _func1, const function2& _func2, const function3& _func3) : my_func1(_func1), my_func2(_func2), my_func3(_func3), is_recycled(false) {} | |
|     }; | |
| 
 | |
|     // Creates and spawns child tasks | |
|     class parallel_invoke_helper : public empty_task { | |
|     public: | |
|         // Dummy functor class | |
|         class parallel_invoke_noop { | |
|         public: | |
|             void operator() () const {} | |
|         }; | |
|         // Creates a helper object with user-defined number of children expected | |
|         parallel_invoke_helper(int number_of_children) | |
|         { | |
|             set_ref_count(number_of_children + 1); | |
|         } | |
|         // Adds child task and spawns it | |
|         template <typename function> | |
|         void add_child (const function &_func) | |
|         { | |
|             internal::function_invoker<function>* invoker = new (allocate_child()) internal::function_invoker<function>(_func); | |
|             __TBB_ASSERT(invoker, "Child task allocation failed"); | |
|             spawn(*invoker); | |
|         } | |
| 
 | |
|         // Adds a task with multiple child tasks and spawns it | |
|         // two arguments | |
|         template <typename function1, typename function2> | |
|         void add_children (const function1& _func1, const function2& _func2) | |
|         { | |
|             // The third argument is dummy, it is ignored actually. | |
|             parallel_invoke_noop noop; | |
|             internal::spawner<2, function1, function2, parallel_invoke_noop>& sub_root = *new(allocate_child())internal::spawner<2, function1, function2, parallel_invoke_noop>(_func1, _func2, noop); | |
|             spawn(sub_root); | |
|         } | |
|         // three arguments | |
|         template <typename function1, typename function2, typename function3> | |
|         void add_children (const function1& _func1, const function2& _func2, const function3& _func3) | |
|         { | |
|             internal::spawner<3, function1, function2, function3>& sub_root = *new(allocate_child())internal::spawner<3, function1, function2, function3>(_func1, _func2, _func3); | |
|             spawn(sub_root); | |
|         } | |
| 
 | |
|         // Waits for all child tasks | |
|         template <typename F0> | |
|         void run_and_finish(const F0& f0) | |
|         { | |
|             internal::function_invoker<F0>* invoker = new (allocate_child()) internal::function_invoker<F0>(f0); | |
|             __TBB_ASSERT(invoker, "Child task allocation failed"); | |
|             spawn_and_wait_for_all(*invoker); | |
|         } | |
|     }; | |
|     // The class destroys root if exception occurred as well as in normal case | |
|     class parallel_invoke_cleaner: internal::no_copy { | |
|     public: | |
| #if __TBB_TASK_GROUP_CONTEXT | |
|         parallel_invoke_cleaner(int number_of_children, tbb::task_group_context& context) | |
|             : root(*new(task::allocate_root(context)) internal::parallel_invoke_helper(number_of_children)) | |
| #else | |
|         parallel_invoke_cleaner(int number_of_children, tbb::task_group_context&) | |
|             : root(*new(task::allocate_root()) internal::parallel_invoke_helper(number_of_children)) | |
| #endif /* !__TBB_TASK_GROUP_CONTEXT */ | |
|         {} | |
| 
 | |
|         ~parallel_invoke_cleaner(){ | |
|             root.destroy(root); | |
|         } | |
|         internal::parallel_invoke_helper& root; | |
|     }; | |
| } // namespace internal | |
| //! @endcond | |
|  | |
| /** \name parallel_invoke | |
|     **/ | |
| //@{ | |
| //! Executes a list of tasks in parallel and waits for all tasks to complete. | |
| /** @ingroup algorithms */ | |
| 
 | |
| // parallel_invoke with user-defined context | |
| // two arguments | |
| template<typename F0, typename F1 > | |
| void parallel_invoke(const F0& f0, const F1& f1, tbb::task_group_context& context) { | |
|     internal::parallel_invoke_cleaner cleaner(2, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_child(f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // three arguments | |
| template<typename F0, typename F1, typename F2 > | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, tbb::task_group_context& context) { | |
|     internal::parallel_invoke_cleaner cleaner(3, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_child(f2); | |
|     root.add_child(f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // four arguments | |
| template<typename F0, typename F1, typename F2, typename F3> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(4, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_child(f3); | |
|     root.add_child(f2); | |
|     root.add_child(f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // five arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4 > | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(3, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_children(f4, f3); | |
|     root.add_children(f2, f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // six arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(3, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_children(f5, f4, f3); | |
|     root.add_children(f2, f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // seven arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(3, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_children(f6, f5, f4); | |
|     root.add_children(f3, f2, f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // eight arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, | |
|          typename F5, typename F6, typename F7> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, const F7& f7, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(4, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_children(f7, f6, f5); | |
|     root.add_children(f4, f3); | |
|     root.add_children(f2, f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // nine arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, | |
|          typename F5, typename F6, typename F7, typename F8> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(4, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_children(f8, f7, f6); | |
|     root.add_children(f5, f4, f3); | |
|     root.add_children(f2, f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // ten arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, | |
|          typename F5, typename F6, typename F7, typename F8, typename F9> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9, | |
|                      tbb::task_group_context& context) | |
| { | |
|     internal::parallel_invoke_cleaner cleaner(4, context); | |
|     internal::parallel_invoke_helper& root = cleaner.root; | |
| 
 | |
|     root.add_children(f9, f8, f7); | |
|     root.add_children(f6, f5, f4); | |
|     root.add_children(f3, f2, f1); | |
| 
 | |
|     root.run_and_finish(f0); | |
| } | |
| 
 | |
| // two arguments | |
| template<typename F0, typename F1> | |
| void parallel_invoke(const F0& f0, const F1& f1) { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1>(f0, f1, context); | |
| } | |
| // three arguments | |
| template<typename F0, typename F1, typename F2> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2) { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2>(f0, f1, f2, context); | |
| } | |
| // four arguments | |
| template<typename F0, typename F1, typename F2, typename F3 > | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3) { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3>(f0, f1, f2, f3, context); | |
| } | |
| // five arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4) { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3, F4>(f0, f1, f2, f3, f4, context); | |
| } | |
| // six arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, const F5& f5) { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3, F4, F5>(f0, f1, f2, f3, f4, f5, context); | |
| } | |
| // seven arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, typename F5, typename F6> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6) | |
| { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3, F4, F5, F6>(f0, f1, f2, f3, f4, f5, f6, context); | |
| } | |
| // eigth arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, | |
|          typename F5, typename F6, typename F7> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, const F7& f7) | |
| { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7>(f0, f1, f2, f3, f4, f5, f6, f7, context); | |
| } | |
| // nine arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, | |
|          typename F5, typename F6, typename F7, typename F8> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, const F7& f7, const F8& f8) | |
| { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8>(f0, f1, f2, f3, f4, f5, f6, f7, f8, context); | |
| } | |
| // ten arguments | |
| template<typename F0, typename F1, typename F2, typename F3, typename F4, | |
|          typename F5, typename F6, typename F7, typename F8, typename F9> | |
| void parallel_invoke(const F0& f0, const F1& f1, const F2& f2, const F3& f3, const F4& f4, | |
|                      const F5& f5, const F6& f6, const F7& f7, const F8& f8, const F9& f9) | |
| { | |
|     task_group_context context; | |
|     parallel_invoke<F0, F1, F2, F3, F4, F5, F6, F7, F8, F9>(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, context); | |
| } | |
| 
 | |
| //@} | |
|  | |
| } // namespace | |
|  | |
| #endif /* __TBB_parallel_invoke_H */
 |