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.
		
		
		
		
		
			
		
			
				
					
					
						
							252 lines
						
					
					
						
							7.1 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							252 lines
						
					
					
						
							7.1 KiB
						
					
					
				
								/*
							 | 
						|
								    Copyright 2005-2013 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_task_group_H
							 | 
						|
								#define __TBB_task_group_H
							 | 
						|
								
							 | 
						|
								#include "task.h"
							 | 
						|
								#include "tbb_exception.h"
							 | 
						|
								
							 | 
						|
								#if __TBB_TASK_GROUP_CONTEXT
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								namespace internal {
							 | 
						|
								    template<typename F> class task_handle_task;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								template<typename F>
							 | 
						|
								class task_handle : internal::no_assign {
							 | 
						|
								    template<typename _F> friend class internal::task_handle_task;
							 | 
						|
								
							 | 
						|
								    static const intptr_t scheduled = 0x1;
							 | 
						|
								
							 | 
						|
								    F my_func;
							 | 
						|
								    intptr_t my_state;
							 | 
						|
								
							 | 
						|
								    void mark_scheduled () {
							 | 
						|
								        // The check here is intentionally lax to avoid the impact of interlocked operation
							 | 
						|
								        if ( my_state & scheduled )
							 | 
						|
								            internal::throw_exception( internal::eid_invalid_multiple_scheduling );
							 | 
						|
								        my_state |= scheduled;
							 | 
						|
								    }
							 | 
						|
								public:
							 | 
						|
								    task_handle( const F& f ) : my_func(f), my_state(0) {}
							 | 
						|
								
							 | 
						|
								    void operator() () const { my_func(); }
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								enum task_group_status {
							 | 
						|
								    not_complete,
							 | 
						|
								    complete,
							 | 
						|
								    canceled
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								namespace internal {
							 | 
						|
								
							 | 
						|
								// Suppress gratuitous warnings from icc 11.0 when lambda expressions are used in instances of function_task.
							 | 
						|
								//#pragma warning(disable: 588)
							 | 
						|
								
							 | 
						|
								template<typename F>
							 | 
						|
								class function_task : public task {
							 | 
						|
								    F my_func;
							 | 
						|
								    /*override*/ task* execute() {
							 | 
						|
								        my_func();
							 | 
						|
								        return NULL;
							 | 
						|
								    }
							 | 
						|
								public:
							 | 
						|
								    function_task( const F& f ) : my_func(f) {}
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								template<typename F>
							 | 
						|
								class task_handle_task : public task {
							 | 
						|
								    task_handle<F>& my_handle;
							 | 
						|
								    /*override*/ task* execute() {
							 | 
						|
								        my_handle();
							 | 
						|
								        return NULL;
							 | 
						|
								    }
							 | 
						|
								public:
							 | 
						|
								    task_handle_task( task_handle<F>& h ) : my_handle(h) { h.mark_scheduled(); }
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								class task_group_base : internal::no_copy {
							 | 
						|
								protected:
							 | 
						|
								    empty_task* my_root;
							 | 
						|
								    task_group_context my_context;
							 | 
						|
								
							 | 
						|
								    task& owner () { return *my_root; }
							 | 
						|
								
							 | 
						|
								    template<typename F>
							 | 
						|
								    task_group_status internal_run_and_wait( F& f ) {
							 | 
						|
								        __TBB_TRY {
							 | 
						|
								            if ( !my_context.is_group_execution_cancelled() )
							 | 
						|
								                f();
							 | 
						|
								        } __TBB_CATCH( ... ) {
							 | 
						|
								            my_context.register_pending_exception();
							 | 
						|
								        }
							 | 
						|
								        return wait();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    template<typename F, typename Task>
							 | 
						|
								    void internal_run( F& f ) {
							 | 
						|
								        owner().spawn( *new( owner().allocate_additional_child_of(*my_root) ) Task(f) );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    task_group_base( uintptr_t traits = 0 )
							 | 
						|
								        : my_context(task_group_context::bound, task_group_context::default_traits | traits)
							 | 
						|
								    {
							 | 
						|
								        my_root = new( task::allocate_root(my_context) ) empty_task;
							 | 
						|
								        my_root->set_ref_count(1);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    ~task_group_base() {
							 | 
						|
								        if( my_root->ref_count() > 1 ) {
							 | 
						|
								            bool stack_unwinding_in_progress = std::uncaught_exception();
							 | 
						|
								            // Always attempt to do proper cleanup to avoid inevitable memory corruption 
							 | 
						|
								            // in case of missing wait (for the sake of better testability & debuggability)
							 | 
						|
								            if ( !is_canceling() )
							 | 
						|
								                cancel();
							 | 
						|
								            __TBB_TRY {
							 | 
						|
								                my_root->wait_for_all();
							 | 
						|
								            } __TBB_CATCH (...) {
							 | 
						|
								                task::destroy(*my_root);
							 | 
						|
								                __TBB_RETHROW();
							 | 
						|
								            }
							 | 
						|
								            task::destroy(*my_root);
							 | 
						|
								            if ( !stack_unwinding_in_progress )
							 | 
						|
								                internal::throw_exception( internal::eid_missing_wait );
							 | 
						|
								        }
							 | 
						|
								        else {
							 | 
						|
								            task::destroy(*my_root);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    template<typename F>
							 | 
						|
								    void run( task_handle<F>& h ) {
							 | 
						|
								        internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    task_group_status wait() {
							 | 
						|
								        __TBB_TRY {
							 | 
						|
								            my_root->wait_for_all();
							 | 
						|
								        } __TBB_CATCH( ... ) {
							 | 
						|
								            my_context.reset();
							 | 
						|
								            __TBB_RETHROW();
							 | 
						|
								        }
							 | 
						|
								        if ( my_context.is_group_execution_cancelled() ) {
							 | 
						|
								            my_context.reset();
							 | 
						|
								            return canceled;
							 | 
						|
								        }
							 | 
						|
								        return complete;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    bool is_canceling() {
							 | 
						|
								        return my_context.is_group_execution_cancelled();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    void cancel() {
							 | 
						|
								        my_context.cancel_group_execution();
							 | 
						|
								    }
							 | 
						|
								}; // class task_group_base
							 | 
						|
								
							 | 
						|
								} // namespace internal
							 | 
						|
								
							 | 
						|
								class task_group : public internal::task_group_base {
							 | 
						|
								public:
							 | 
						|
								    task_group () : task_group_base( task_group_context::concurrent_wait ) {}
							 | 
						|
								
							 | 
						|
								#if TBB_DEPRECATED
							 | 
						|
								    ~task_group() __TBB_TRY {
							 | 
						|
								        __TBB_ASSERT( my_root->ref_count() != 0, NULL );
							 | 
						|
								        if( my_root->ref_count() > 1 )
							 | 
						|
								            my_root->wait_for_all();
							 | 
						|
								    }
							 | 
						|
								#if TBB_USE_EXCEPTIONS
							 | 
						|
								    catch (...) {
							 | 
						|
								        // Have to destroy my_root here as the base class destructor won't be called
							 | 
						|
								        task::destroy(*my_root);
							 | 
						|
								        throw;
							 | 
						|
								    }
							 | 
						|
								#endif /* TBB_USE_EXCEPTIONS */
							 | 
						|
								#endif /* TBB_DEPRECATED */
							 | 
						|
								
							 | 
						|
								#if __SUNPRO_CC
							 | 
						|
								    template<typename F>
							 | 
						|
								    void run( task_handle<F>& h ) {
							 | 
						|
								        internal_run< task_handle<F>, internal::task_handle_task<F> >( h );
							 | 
						|
								    }
							 | 
						|
								#else
							 | 
						|
								    using task_group_base::run;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    template<typename F>
							 | 
						|
								    void run( const F& f ) {
							 | 
						|
								        internal_run< const F, internal::function_task<F> >( f );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    template<typename F>
							 | 
						|
								    task_group_status run_and_wait( const F& f ) {
							 | 
						|
								        return internal_run_and_wait<const F>( f );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    template<typename F>
							 | 
						|
								    task_group_status run_and_wait( task_handle<F>& h ) {
							 | 
						|
								      return internal_run_and_wait< task_handle<F> >( h );
							 | 
						|
								    }
							 | 
						|
								}; // class task_group
							 | 
						|
								
							 | 
						|
								class structured_task_group : public internal::task_group_base {
							 | 
						|
								public:
							 | 
						|
								    template<typename F>
							 | 
						|
								    task_group_status run_and_wait ( task_handle<F>& h ) {
							 | 
						|
								        return internal_run_and_wait< task_handle<F> >( h );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    task_group_status wait() {
							 | 
						|
								        task_group_status res = task_group_base::wait();
							 | 
						|
								        my_root->set_ref_count(1);
							 | 
						|
								        return res;
							 | 
						|
								    }
							 | 
						|
								}; // class structured_task_group
							 | 
						|
								
							 | 
						|
								inline 
							 | 
						|
								bool is_current_task_group_canceling() {
							 | 
						|
								    return task::self().is_cancelled();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								template<class F>
							 | 
						|
								task_handle<F> make_task( const F& f ) {
							 | 
						|
								    return task_handle<F>( f );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								} // namespace tbb
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_TASK_GROUP_CONTEXT */
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_task_group_H */
							 |