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.
		
		
		
		
		
			
		
			
				
					
					
						
							420 lines
						
					
					
						
							14 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							420 lines
						
					
					
						
							14 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_concurrent_queue_H
							 | 
						|
								#define __TBB_concurrent_queue_H
							 | 
						|
								
							 | 
						|
								#include "internal/_concurrent_queue_impl.h"
							 | 
						|
								
							 | 
						|
								namespace tbb {
							 | 
						|
								
							 | 
						|
								namespace strict_ppl {
							 | 
						|
								
							 | 
						|
								//! A high-performance thread-safe non-blocking concurrent queue.
							 | 
						|
								/** Multiple threads may each push and pop concurrently.
							 | 
						|
								    Assignment construction is not allowed.
							 | 
						|
								    @ingroup containers */
							 | 
						|
								template<typename T, typename A = cache_aligned_allocator<T> > 
							 | 
						|
								class concurrent_queue: public internal::concurrent_queue_base_v3<T> {
							 | 
						|
								    template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
							 | 
						|
								
							 | 
						|
								    //! Allocator type
							 | 
						|
								    typedef typename A::template rebind<char>::other page_allocator_type;
							 | 
						|
								    page_allocator_type my_allocator;
							 | 
						|
								
							 | 
						|
								    //! Allocates a block of size n (bytes)
							 | 
						|
								    /*override*/ virtual void *allocate_block( size_t n ) {
							 | 
						|
								        void *b = reinterpret_cast<void*>(my_allocator.allocate( n ));
							 | 
						|
								        if( !b )
							 | 
						|
								            internal::throw_exception(internal::eid_bad_alloc); 
							 | 
						|
								        return b;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Deallocates block created by allocate_block.
							 | 
						|
								    /*override*/ virtual void deallocate_block( void *b, size_t n ) {
							 | 
						|
								        my_allocator.deallocate( reinterpret_cast<char*>(b), n );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    //! Element type in the queue.
							 | 
						|
								    typedef T value_type;
							 | 
						|
								
							 | 
						|
								    //! Reference type
							 | 
						|
								    typedef T& reference;
							 | 
						|
								
							 | 
						|
								    //! Const reference type
							 | 
						|
								    typedef const T& const_reference;
							 | 
						|
								
							 | 
						|
								    //! Integral type for representing size of the queue.
							 | 
						|
								    typedef size_t size_type;
							 | 
						|
								
							 | 
						|
								    //! Difference type for iterator
							 | 
						|
								    typedef ptrdiff_t difference_type;
							 | 
						|
								
							 | 
						|
								    //! Allocator type
							 | 
						|
								    typedef A allocator_type;
							 | 
						|
								
							 | 
						|
								    //! Construct empty queue
							 | 
						|
								    explicit concurrent_queue(const allocator_type& a = allocator_type()) : 
							 | 
						|
								        my_allocator( a )
							 | 
						|
								    {
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! [begin,end) constructor
							 | 
						|
								    template<typename InputIterator>
							 | 
						|
								    concurrent_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
							 | 
						|
								        my_allocator( a )
							 | 
						|
								    {
							 | 
						|
								        for( ; begin != end; ++begin )
							 | 
						|
								            this->internal_push(&*begin);
							 | 
						|
								    }
							 | 
						|
								    
							 | 
						|
								    //! Copy constructor
							 | 
						|
								    concurrent_queue( const concurrent_queue& src, const allocator_type& a = allocator_type()) : 
							 | 
						|
								        internal::concurrent_queue_base_v3<T>(), my_allocator( a )
							 | 
						|
								    {
							 | 
						|
								        this->assign( src );
							 | 
						|
								    }
							 | 
						|
								    
							 | 
						|
								    //! Destroy queue
							 | 
						|
								    ~concurrent_queue();
							 | 
						|
								
							 | 
						|
								    //! Enqueue an item at tail of queue.
							 | 
						|
								    void push( const T& source ) {
							 | 
						|
								        this->internal_push( &source );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Attempt to dequeue an item from head of queue.
							 | 
						|
								    /** Does not wait for item to become available.
							 | 
						|
								        Returns true if successful; false otherwise. */
							 | 
						|
								    bool try_pop( T& result ) {
							 | 
						|
								        return this->internal_try_pop( &result );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Return the number of items in the queue; thread unsafe
							 | 
						|
								    size_type unsafe_size() const {return this->internal_size();}
							 | 
						|
								
							 | 
						|
								    //! Equivalent to size()==0.
							 | 
						|
								    bool empty() const {return this->internal_empty();}
							 | 
						|
								
							 | 
						|
								    //! Clear the queue. not thread-safe.
							 | 
						|
								    void clear() ;
							 | 
						|
								
							 | 
						|
								    //! Return allocator object
							 | 
						|
								    allocator_type get_allocator() const { return this->my_allocator; }
							 | 
						|
								
							 | 
						|
								    typedef internal::concurrent_queue_iterator<concurrent_queue,T> iterator;
							 | 
						|
								    typedef internal::concurrent_queue_iterator<concurrent_queue,const T> const_iterator;
							 | 
						|
								
							 | 
						|
								    //------------------------------------------------------------------------
							 | 
						|
								    // The iterators are intended only for debugging.  They are slow and not thread safe.
							 | 
						|
								    //------------------------------------------------------------------------
							 | 
						|
								    iterator unsafe_begin() {return iterator(*this);}
							 | 
						|
								    iterator unsafe_end() {return iterator();}
							 | 
						|
								    const_iterator unsafe_begin() const {return const_iterator(*this);}
							 | 
						|
								    const_iterator unsafe_end() const {return const_iterator();}
							 | 
						|
								} ;
							 | 
						|
								
							 | 
						|
								template<typename T, class A>
							 | 
						|
								concurrent_queue<T,A>::~concurrent_queue() {
							 | 
						|
								    clear();
							 | 
						|
								    this->internal_finish_clear();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								template<typename T, class A>
							 | 
						|
								void concurrent_queue<T,A>::clear() {
							 | 
						|
								    while( !empty() ) {
							 | 
						|
								        T value;
							 | 
						|
								        this->internal_try_pop(&value);
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								} // namespace strict_ppl
							 | 
						|
								    
							 | 
						|
								//! A high-performance thread-safe blocking concurrent bounded queue.
							 | 
						|
								/** This is the pre-PPL TBB concurrent queue which supports boundedness and blocking semantics.
							 | 
						|
								    Note that method names agree with the PPL-style concurrent queue.
							 | 
						|
								    Multiple threads may each push and pop concurrently.
							 | 
						|
								    Assignment construction is not allowed.
							 | 
						|
								    @ingroup containers */
							 | 
						|
								template<typename T, class A = cache_aligned_allocator<T> >
							 | 
						|
								class concurrent_bounded_queue: public internal::concurrent_queue_base_v3 {
							 | 
						|
								    template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
							 | 
						|
								
							 | 
						|
								    //! Allocator type
							 | 
						|
								    typedef typename A::template rebind<char>::other page_allocator_type;
							 | 
						|
								    page_allocator_type my_allocator;
							 | 
						|
								
							 | 
						|
								    typedef typename concurrent_queue_base_v3::padded_page<T> padded_page;
							 | 
						|
								 
							 | 
						|
								    //! Class used to ensure exception-safety of method "pop" 
							 | 
						|
								    class destroyer: internal::no_copy {
							 | 
						|
								        T& my_value;
							 | 
						|
								    public:
							 | 
						|
								        destroyer( T& value ) : my_value(value) {}
							 | 
						|
								        ~destroyer() {my_value.~T();}          
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    T& get_ref( page& p, size_t index ) {
							 | 
						|
								        __TBB_ASSERT( index<items_per_page, NULL );
							 | 
						|
								        return (&static_cast<padded_page*>(static_cast<void*>(&p))->last)[index];
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /*override*/ virtual void copy_item( page& dst, size_t index, const void* src ) {
							 | 
						|
								        new( &get_ref(dst,index) ) T(*static_cast<const T*>(src)); 
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /*override*/ virtual void copy_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) {
							 | 
						|
								        new( &get_ref(dst,dindex) ) T( get_ref( const_cast<page&>(src), sindex ) );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /*override*/ virtual void assign_and_destroy_item( void* dst, page& src, size_t index ) {
							 | 
						|
								        T& from = get_ref(src,index);
							 | 
						|
								        destroyer d(from);
							 | 
						|
								        *static_cast<T*>(dst) = from;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /*override*/ virtual page *allocate_page() {
							 | 
						|
								        size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
							 | 
						|
								        page *p = reinterpret_cast<page*>(my_allocator.allocate( n ));
							 | 
						|
								        if( !p )
							 | 
						|
								            internal::throw_exception(internal::eid_bad_alloc); 
							 | 
						|
								        return p;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /*override*/ virtual void deallocate_page( page *p ) {
							 | 
						|
								        size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
							 | 
						|
								        my_allocator.deallocate( reinterpret_cast<char*>(p), n );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    //! Element type in the queue.
							 | 
						|
								    typedef T value_type;
							 | 
						|
								
							 | 
						|
								    //! Allocator type
							 | 
						|
								    typedef A allocator_type;
							 | 
						|
								
							 | 
						|
								    //! Reference type
							 | 
						|
								    typedef T& reference;
							 | 
						|
								
							 | 
						|
								    //! Const reference type
							 | 
						|
								    typedef const T& const_reference;
							 | 
						|
								
							 | 
						|
								    //! Integral type for representing size of the queue.
							 | 
						|
								    /** Note that the size_type is a signed integral type.
							 | 
						|
								        This is because the size can be negative if there are pending pops without corresponding pushes. */
							 | 
						|
								    typedef std::ptrdiff_t size_type;
							 | 
						|
								
							 | 
						|
								    //! Difference type for iterator
							 | 
						|
								    typedef std::ptrdiff_t difference_type;
							 | 
						|
								
							 | 
						|
								    //! Construct empty queue
							 | 
						|
								    explicit concurrent_bounded_queue(const allocator_type& a = allocator_type()) : 
							 | 
						|
								        concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
							 | 
						|
								    {
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Copy constructor
							 | 
						|
								    concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a = allocator_type()) : 
							 | 
						|
								        concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
							 | 
						|
								    {
							 | 
						|
								        assign( src );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! [begin,end) constructor
							 | 
						|
								    template<typename InputIterator>
							 | 
						|
								    concurrent_bounded_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
							 | 
						|
								        concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
							 | 
						|
								    {
							 | 
						|
								        for( ; begin != end; ++begin )
							 | 
						|
								            internal_push_if_not_full(&*begin);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Destroy queue
							 | 
						|
								    ~concurrent_bounded_queue();
							 | 
						|
								
							 | 
						|
								    //! Enqueue an item at tail of queue.
							 | 
						|
								    void push( const T& source ) {
							 | 
						|
								        internal_push( &source );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Dequeue item from head of queue.
							 | 
						|
								    /** Block until an item becomes available, and then dequeue it. */
							 | 
						|
								    void pop( T& destination ) {
							 | 
						|
								        internal_pop( &destination );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#if TBB_USE_EXCEPTIONS
							 | 
						|
								    //! Abort all pending queue operations
							 | 
						|
								    void abort() {
							 | 
						|
								        internal_abort();
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    //! Enqueue an item at tail of queue if queue is not already full.
							 | 
						|
								    /** Does not wait for queue to become not full.
							 | 
						|
								        Returns true if item is pushed; false if queue was already full. */
							 | 
						|
								    bool try_push( const T& source ) {
							 | 
						|
								        return internal_push_if_not_full( &source );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Attempt to dequeue an item from head of queue.
							 | 
						|
								    /** Does not wait for item to become available.
							 | 
						|
								        Returns true if successful; false otherwise. */
							 | 
						|
								    bool try_pop( T& destination ) {
							 | 
						|
								        return internal_pop_if_present( &destination );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Return number of pushes minus number of pops.
							 | 
						|
								    /** Note that the result can be negative if there are pops waiting for the 
							 | 
						|
								        corresponding pushes.  The result can also exceed capacity() if there 
							 | 
						|
								        are push operations in flight. */
							 | 
						|
								    size_type size() const {return internal_size();}
							 | 
						|
								
							 | 
						|
								    //! Equivalent to size()<=0.
							 | 
						|
								    bool empty() const {return internal_empty();}
							 | 
						|
								
							 | 
						|
								    //! Maximum number of allowed elements
							 | 
						|
								    size_type capacity() const {
							 | 
						|
								        return my_capacity;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Set the capacity
							 | 
						|
								    /** Setting the capacity to 0 causes subsequent try_push operations to always fail,
							 | 
						|
								        and subsequent push operations to block forever. */
							 | 
						|
								    void set_capacity( size_type new_capacity ) {
							 | 
						|
								        internal_set_capacity( new_capacity, sizeof(T) );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! return allocator object
							 | 
						|
								    allocator_type get_allocator() const { return this->my_allocator; }
							 | 
						|
								
							 | 
						|
								    //! clear the queue. not thread-safe.
							 | 
						|
								    void clear() ;
							 | 
						|
								
							 | 
						|
								    typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,T> iterator;
							 | 
						|
								    typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,const T> const_iterator;
							 | 
						|
								
							 | 
						|
								    //------------------------------------------------------------------------
							 | 
						|
								    // The iterators are intended only for debugging.  They are slow and not thread safe.
							 | 
						|
								    //------------------------------------------------------------------------
							 | 
						|
								    iterator unsafe_begin() {return iterator(*this);}
							 | 
						|
								    iterator unsafe_end() {return iterator();}
							 | 
						|
								    const_iterator unsafe_begin() const {return const_iterator(*this);}
							 | 
						|
								    const_iterator unsafe_end() const {return const_iterator();}
							 | 
						|
								
							 | 
						|
								}; 
							 | 
						|
								
							 | 
						|
								template<typename T, class A>
							 | 
						|
								concurrent_bounded_queue<T,A>::~concurrent_bounded_queue() {
							 | 
						|
								    clear();
							 | 
						|
								    internal_finish_clear();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								template<typename T, class A>
							 | 
						|
								void concurrent_bounded_queue<T,A>::clear() {
							 | 
						|
								    while( !empty() ) {
							 | 
						|
								        T value;
							 | 
						|
								        internal_pop_if_present(&value);
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								namespace deprecated {
							 | 
						|
								
							 | 
						|
								//! A high-performance thread-safe blocking concurrent bounded queue.
							 | 
						|
								/** This is the pre-PPL TBB concurrent queue which support boundedness and blocking semantics.
							 | 
						|
								    Note that method names agree with the PPL-style concurrent queue.
							 | 
						|
								    Multiple threads may each push and pop concurrently.
							 | 
						|
								    Assignment construction is not allowed.
							 | 
						|
								    @ingroup containers */
							 | 
						|
								template<typename T, class A = cache_aligned_allocator<T> > 
							 | 
						|
								class concurrent_queue: public concurrent_bounded_queue<T,A> {
							 | 
						|
								#if !__TBB_TEMPLATE_FRIENDS_BROKEN
							 | 
						|
								    template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
							 | 
						|
								#endif 
							 | 
						|
								
							 | 
						|
								public:
							 | 
						|
								    //! Construct empty queue
							 | 
						|
								    explicit concurrent_queue(const A& a = A()) : 
							 | 
						|
								        concurrent_bounded_queue<T,A>( a )
							 | 
						|
								    {
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Copy constructor
							 | 
						|
								    concurrent_queue( const concurrent_queue& src, const A& a = A()) : 
							 | 
						|
								        concurrent_bounded_queue<T,A>( src, a )
							 | 
						|
								    {
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! [begin,end) constructor
							 | 
						|
								    template<typename InputIterator>
							 | 
						|
								    concurrent_queue( InputIterator b /*begin*/, InputIterator e /*end*/, const A& a = A()) :
							 | 
						|
								        concurrent_bounded_queue<T,A>( b, e, a )
							 | 
						|
								    {
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Enqueue an item at tail of queue if queue is not already full.
							 | 
						|
								    /** Does not wait for queue to become not full.
							 | 
						|
								        Returns true if item is pushed; false if queue was already full. */
							 | 
						|
								    bool push_if_not_full( const T& source ) {
							 | 
						|
								        return this->try_push( source );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    //! Attempt to dequeue an item from head of queue.
							 | 
						|
								    /** Does not wait for item to become available.
							 | 
						|
								        Returns true if successful; false otherwise. 
							 | 
						|
								        @deprecated Use try_pop()
							 | 
						|
								        */
							 | 
						|
								    bool pop_if_present( T& destination ) {
							 | 
						|
								        return this->try_pop( destination );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    typedef typename concurrent_bounded_queue<T,A>::iterator iterator;
							 | 
						|
								    typedef typename concurrent_bounded_queue<T,A>::const_iterator const_iterator;
							 | 
						|
								    //
							 | 
						|
								    //------------------------------------------------------------------------
							 | 
						|
								    // The iterators are intended only for debugging.  They are slow and not thread safe.
							 | 
						|
								    //------------------------------------------------------------------------
							 | 
						|
								    iterator begin() {return this->unsafe_begin();}
							 | 
						|
								    iterator end() {return this->unsafe_end();}
							 | 
						|
								    const_iterator begin() const {return this->unsafe_begin();}
							 | 
						|
								    const_iterator end() const {return this->unsafe_end();}
							 | 
						|
								}; 
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								    
							 | 
						|
								
							 | 
						|
								#if TBB_DEPRECATED
							 | 
						|
								using deprecated::concurrent_queue;
							 | 
						|
								#else
							 | 
						|
								using strict_ppl::concurrent_queue;    
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								} // namespace tbb
							 | 
						|
								
							 | 
						|
								#endif /* __TBB_concurrent_queue_H */
							 |