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.
		
		
		
		
		
			
		
			
				
					
					
						
							228 lines
						
					
					
						
							8.2 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							228 lines
						
					
					
						
							8.2 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_arena_H
							 | 
						|
								#define __TBB_task_arena_H
							 | 
						|
								
							 | 
						|
								#include "task.h"
							 | 
						|
								#include "tbb_exception.h"
							 | 
						|
								
							 | 
						|
								#if __TBB_TASK_ARENA
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								//! @cond INTERNAL
							 | 
						|
								namespace internal {
							 | 
						|
								    //! Internal to library. Should not be used by clients.
							 | 
						|
								    /** @ingroup task_scheduling */
							 | 
						|
								    class arena;
							 | 
						|
								    class task_scheduler_observer_v3;
							 | 
						|
								} // namespace internal
							 | 
						|
								//! @endcond
							 | 
						|
								
							 | 
						|
								namespace interface6 {
							 | 
						|
								//! @cond INTERNAL
							 | 
						|
								namespace internal {
							 | 
						|
								using namespace tbb::internal;
							 | 
						|
								
							 | 
						|
								template<typename F>
							 | 
						|
								class enqueued_function_task : public task { // TODO: reuse from task_group?
							 | 
						|
								    F my_func;
							 | 
						|
								    /*override*/ task* execute() {
							 | 
						|
								        my_func();
							 | 
						|
								        return NULL;
							 | 
						|
								    }
							 | 
						|
								public:
							 | 
						|
								    enqueued_function_task ( const F& f ) : my_func(f) {}
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								class delegate_base : no_assign {
							 | 
						|
								public:
							 | 
						|
								    virtual void operator()() const = 0;
							 | 
						|
								    virtual ~delegate_base() {}
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								template<typename F>
							 | 
						|
								class delegated_function : public delegate_base {
							 | 
						|
								    F &my_func;
							 | 
						|
								    /*override*/ void operator()() const {
							 | 
						|
								        my_func();
							 | 
						|
								    }
							 | 
						|
								public:
							 | 
						|
								    delegated_function ( F& f ) : my_func(f) {}
							 | 
						|
								};
							 | 
						|
								} // namespace internal
							 | 
						|
								//! @endcond
							 | 
						|
								
							 | 
						|
								/** 1-to-1 proxy representation class of scheduler's arena
							 | 
						|
								 * Constructors set up settings only, real construction is deferred till the first method invocation
							 | 
						|
								 * TODO: A side effect of this is that it's impossible to create a const task_arena object. Rethink?
							 | 
						|
								 * Destructor only removes one of the references to the inner arena representation.
							 | 
						|
								 * Final destruction happens when all the references (and the work) are gone.
							 | 
						|
								 */
							 | 
						|
								class task_arena {
							 | 
						|
								    friend class internal::task_scheduler_observer_v3;
							 | 
						|
								    //! Concurrency level for deferred initialization
							 | 
						|
								    int my_max_concurrency;
							 | 
						|
								
							 | 
						|
								    //! Reserved master slots
							 | 
						|
								    unsigned my_master_slots;
							 | 
						|
								
							 | 
						|
								    //! NULL if not currently initialized.
							 | 
						|
								    internal::arena* my_arena;
							 | 
						|
								
							 | 
						|
								    // Initialization flag enabling compiler to throw excessive lazy initialization checks
							 | 
						|
								    bool my_initialized;
							 | 
						|
								
							 | 
						|
								    // const methods help to optimize the !my_arena check TODO: check, IDEA: move to base-class?
							 | 
						|
								    void __TBB_EXPORTED_METHOD internal_initialize( );
							 | 
						|
								    void __TBB_EXPORTED_METHOD internal_terminate( );
							 | 
						|
								    void __TBB_EXPORTED_METHOD internal_enqueue( task&, intptr_t ) const;
							 | 
						|
								    void __TBB_EXPORTED_METHOD internal_execute( internal::delegate_base& ) const;
							 | 
						|
								    void __TBB_EXPORTED_METHOD internal_wait() const;
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    //! Typedef for number of threads that is automatic.
							 | 
						|
								    static const int automatic = -1; // any value < 1 means 'automatic'
							 | 
						|
								
							 | 
						|
								    //! Creates task_arena with certain concurrency limits
							 | 
						|
								    /** @arg max_concurrency specifies total number of slots in arena where threads work
							 | 
						|
								     *  @arg reserved_for_masters specifies number of slots to be used by master threads only.
							 | 
						|
								     *       Value of 1 is default and reflects behavior of implicit arenas.
							 | 
						|
								     **/
							 | 
						|
								    task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1)
							 | 
						|
								        : my_max_concurrency(max_concurrency)
							 | 
						|
								        , my_master_slots(reserved_for_masters)
							 | 
						|
								        , my_arena(0)
							 | 
						|
								        , my_initialized(false)
							 | 
						|
								    {}
							 | 
						|
								
							 | 
						|
								    //! Copies settings from another task_arena
							 | 
						|
								    task_arena(const task_arena &s)
							 | 
						|
								        : my_max_concurrency(s.my_max_concurrency) // copy settings
							 | 
						|
								        , my_master_slots(s.my_master_slots)
							 | 
						|
								        , my_arena(0) // but not the reference or instance
							 | 
						|
								        , my_initialized(false)
							 | 
						|
								    {}
							 | 
						|
								
							 | 
						|
								    inline void initialize() {
							 | 
						|
								        if( !my_initialized ) {
							 | 
						|
								            internal_initialize();
							 | 
						|
								            my_initialized = true;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Overrides concurrency level and forces initialization of internal representation
							 | 
						|
								    inline void initialize(int max_concurrency, unsigned reserved_for_masters = 1) {
							 | 
						|
								        __TBB_ASSERT( !my_arena, "task_arena was initialized already");
							 | 
						|
								        if( !my_initialized ) {
							 | 
						|
								            my_max_concurrency = max_concurrency;
							 | 
						|
								            my_master_slots = reserved_for_masters;
							 | 
						|
								            initialize();
							 | 
						|
								        } // TODO: else throw?
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Removes the reference to the internal arena representation.
							 | 
						|
								    //! Not thread safe wrt concurrent invocations of other methods.
							 | 
						|
								    inline void terminate() {
							 | 
						|
								        if( my_initialized ) {
							 | 
						|
								            internal_terminate();
							 | 
						|
								            my_initialized = false;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Removes the reference to the internal arena representation, and destroys the external object.
							 | 
						|
								    //! Not thread safe wrt concurrent invocations of other methods.
							 | 
						|
								    ~task_arena() {
							 | 
						|
								        terminate();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Returns true if the arena is active (initialized); false otherwise.
							 | 
						|
								    //! The name was chosen to match a task_scheduler_init method with the same semantics.
							 | 
						|
								    bool is_active() const { return my_initialized; }
							 | 
						|
								
							 | 
						|
								    //! Enqueues a task into the arena to process a functor, and immediately returns.
							 | 
						|
								    //! Does not require the calling thread to join the arena
							 | 
						|
								    template<typename F>
							 | 
						|
								    void enqueue( const F& f ) {
							 | 
						|
								        initialize();
							 | 
						|
								        internal_enqueue( *new( task::allocate_root() ) internal::enqueued_function_task<F>(f), 0 );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#if __TBB_TASK_PRIORITY
							 | 
						|
								    //! Enqueues a task with priority p into the arena to process a functor f, and immediately returns.
							 | 
						|
								    //! Does not require the calling thread to join the arena
							 | 
						|
								    template<typename F>
							 | 
						|
								    void enqueue( const F& f, priority_t p ) {
							 | 
						|
								        __TBB_ASSERT( p == priority_low || p == priority_normal || p == priority_high, "Invalid priority level value" );
							 | 
						|
								        initialize();
							 | 
						|
								        internal_enqueue( *new( task::allocate_root() ) internal::enqueued_function_task<F>(f), (intptr_t)p );
							 | 
						|
								    }
							 | 
						|
								#endif// __TBB_TASK_PRIORITY
							 | 
						|
								
							 | 
						|
								    //! Joins the arena and executes a functor, then returns
							 | 
						|
								    //! If not possible to join, wraps the functor into a task, enqueues it and waits for task completion
							 | 
						|
								    //! Can decrement the arena demand for workers, causing a worker to leave and free a slot to the calling thread
							 | 
						|
								    template<typename F>
							 | 
						|
								    void execute(F& f) {
							 | 
						|
								        initialize();
							 | 
						|
								        internal::delegated_function<F> d(f);
							 | 
						|
								        internal_execute( d );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Joins the arena and executes a functor, then returns
							 | 
						|
								    //! If not possible to join, wraps the functor into a task, enqueues it and waits for task completion
							 | 
						|
								    //! Can decrement the arena demand for workers, causing a worker to leave and free a slot to the calling thread
							 | 
						|
								    template<typename F>
							 | 
						|
								    void execute(const F& f) {
							 | 
						|
								        initialize();
							 | 
						|
								        internal::delegated_function<const F> d(f);
							 | 
						|
								        internal_execute( d );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Wait for all work in the arena to be completed
							 | 
						|
								    //! Even submitted by other application threads
							 | 
						|
								    //! Joins arena if/when possible (in the same way as execute())
							 | 
						|
								    void wait_until_empty() {
							 | 
						|
								        initialize();
							 | 
						|
								        internal_wait();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Returns the index, aka slot number, of the calling thread in its current arena
							 | 
						|
								    static int __TBB_EXPORTED_FUNC current_slot();
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								} // namespace interfaceX
							 | 
						|
								
							 | 
						|
								using interface6::task_arena;
							 | 
						|
								
							 | 
						|
								} // namespace tbb
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_TASK_ARENA */
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_task_arena_H */
							 |