Back to home page

EIC code displayed by LXR

 
 

    


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

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_concurrent_queue_H
0018 #define __TBB_concurrent_queue_H
0019 
0020 #define __TBB_concurrent_queue_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022 
0023 #include "internal/_concurrent_queue_impl.h"
0024 #include "internal/_allocator_traits.h"
0025 
0026 namespace tbb {
0027 
0028 namespace strict_ppl {
0029 
0030 //! A high-performance thread-safe non-blocking concurrent queue.
0031 /** Multiple threads may each push and pop concurrently.
0032     Assignment construction is not allowed.
0033     @ingroup containers */
0034 template<typename T, typename A = cache_aligned_allocator<T> >
0035 class concurrent_queue: public internal::concurrent_queue_base_v3<T> {
0036     template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
0037 
0038     //! Allocator type
0039     typedef typename tbb::internal::allocator_rebind<A, char>::type page_allocator_type;
0040     page_allocator_type my_allocator;
0041 
0042     //! Allocates a block of size n (bytes)
0043     virtual void *allocate_block( size_t n ) __TBB_override {
0044         void *b = reinterpret_cast<void*>(my_allocator.allocate( n ));
0045         if( !b )
0046             internal::throw_exception(internal::eid_bad_alloc);
0047         return b;
0048     }
0049 
0050     //! Deallocates block created by allocate_block.
0051     virtual void deallocate_block( void *b, size_t n ) __TBB_override {
0052         my_allocator.deallocate( reinterpret_cast<char*>(b), n );
0053     }
0054 
0055     static void copy_construct_item(T* location, const void* src){
0056         new (location) T(*static_cast<const T*>(src));
0057     }
0058 
0059 #if __TBB_CPP11_RVALUE_REF_PRESENT
0060     static void move_construct_item(T* location, const void* src) {
0061         new (location) T( std::move(*static_cast<T*>(const_cast<void*>(src))) );
0062     }
0063 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
0064 public:
0065     //! Element type in the queue.
0066     typedef T value_type;
0067 
0068     //! Reference type
0069     typedef T& reference;
0070 
0071     //! Const reference type
0072     typedef const T& const_reference;
0073 
0074     //! Integral type for representing size of the queue.
0075     typedef size_t size_type;
0076 
0077     //! Difference type for iterator
0078     typedef ptrdiff_t difference_type;
0079 
0080     //! Allocator type
0081     typedef A allocator_type;
0082 
0083     //! Construct empty queue
0084     explicit concurrent_queue(const allocator_type& a = allocator_type()) :
0085         my_allocator( a )
0086     {
0087     }
0088 
0089     //! [begin,end) constructor
0090     template<typename InputIterator>
0091     concurrent_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
0092         my_allocator( a )
0093     {
0094         for( ; begin != end; ++begin )
0095             this->push(*begin);
0096     }
0097 
0098     //! Copy constructor
0099     concurrent_queue( const concurrent_queue& src, const allocator_type& a = allocator_type()) :
0100         internal::concurrent_queue_base_v3<T>(), my_allocator( a )
0101     {
0102         this->assign( src, copy_construct_item );
0103     }
0104 
0105 #if __TBB_CPP11_RVALUE_REF_PRESENT
0106     //! Move constructors
0107     concurrent_queue( concurrent_queue&& src ) :
0108         internal::concurrent_queue_base_v3<T>(), my_allocator( std::move(src.my_allocator) )
0109     {
0110         this->internal_swap( src );
0111     }
0112 
0113     concurrent_queue( concurrent_queue&& src, const allocator_type& a ) :
0114         internal::concurrent_queue_base_v3<T>(), my_allocator( a )
0115     {
0116         // checking that memory allocated by one instance of allocator can be deallocated
0117         // with another
0118         if( my_allocator == src.my_allocator) {
0119             this->internal_swap( src );
0120         } else {
0121             // allocators are different => performing per-element move
0122             this->assign( src, move_construct_item );
0123             src.clear();
0124         }
0125     }
0126 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
0127 
0128     //! Destroy queue
0129     ~concurrent_queue();
0130 
0131     //! Enqueue an item at tail of queue.
0132     void push( const T& source ) {
0133         this->internal_push( &source, copy_construct_item );
0134     }
0135 
0136 #if __TBB_CPP11_RVALUE_REF_PRESENT
0137     void push( T&& source ) {
0138         this->internal_push( &source, move_construct_item );
0139     }
0140 
0141 #if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0142     template<typename... Arguments>
0143     void emplace( Arguments&&... args ) {
0144         push( T(std::forward<Arguments>( args )...) );
0145     }
0146 #endif //__TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0147 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
0148 
0149     //! Attempt to dequeue an item from head of queue.
0150     /** Does not wait for item to become available.
0151         Returns true if successful; false otherwise. */
0152     bool try_pop( T& result ) {
0153         return this->internal_try_pop( &result );
0154     }
0155 
0156     //! Return the number of items in the queue; thread unsafe
0157     size_type unsafe_size() const {return this->internal_size();}
0158 
0159     //! Equivalent to size()==0.
0160     bool empty() const {return this->internal_empty();}
0161 
0162     //! Clear the queue. not thread-safe.
0163     void clear() ;
0164 
0165     //! Return allocator object
0166     allocator_type get_allocator() const { return this->my_allocator; }
0167 
0168     typedef internal::concurrent_queue_iterator<concurrent_queue,T> iterator;
0169     typedef internal::concurrent_queue_iterator<concurrent_queue,const T> const_iterator;
0170 
0171     //------------------------------------------------------------------------
0172     // The iterators are intended only for debugging.  They are slow and not thread safe.
0173     //------------------------------------------------------------------------
0174     iterator unsafe_begin() {return iterator(*this);}
0175     iterator unsafe_end() {return iterator();}
0176     const_iterator unsafe_begin() const {return const_iterator(*this);}
0177     const_iterator unsafe_end() const {return const_iterator();}
0178 } ;
0179 
0180 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
0181 // Deduction guide for the constructor from two iterators
0182 template<typename InputIterator,
0183          typename T = typename std::iterator_traits<InputIterator>::value_type,
0184          typename A = cache_aligned_allocator<T>
0185 > concurrent_queue(InputIterator, InputIterator, const A& = A())
0186 -> concurrent_queue<T, A>;
0187 #endif /* __TBB_CPP17_DEDUCTION_GUIDES_PRESENT */
0188 
0189 template<typename T, class A>
0190 concurrent_queue<T,A>::~concurrent_queue() {
0191     clear();
0192     this->internal_finish_clear();
0193 }
0194 
0195 template<typename T, class A>
0196 void concurrent_queue<T,A>::clear() {
0197     T value;
0198     while( !empty() ) try_pop(value);
0199 }
0200 
0201 } // namespace strict_ppl
0202 
0203 //! A high-performance thread-safe blocking concurrent bounded queue.
0204 /** This is the pre-PPL TBB concurrent queue which supports boundedness and blocking semantics.
0205     Note that method names agree with the PPL-style concurrent queue.
0206     Multiple threads may each push and pop concurrently.
0207     Assignment construction is not allowed.
0208     @ingroup containers */
0209 template<typename T, class A = cache_aligned_allocator<T> >
0210 class concurrent_bounded_queue: public internal::concurrent_queue_base_v8 {
0211     template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
0212     typedef typename tbb::internal::allocator_rebind<A, char>::type page_allocator_type;
0213 
0214     //! Allocator type
0215     page_allocator_type my_allocator;
0216 
0217     typedef typename concurrent_queue_base_v3::padded_page<T> padded_page;
0218     typedef typename concurrent_queue_base_v3::copy_specifics copy_specifics;
0219 
0220     //! Class used to ensure exception-safety of method "pop"
0221     class destroyer: internal::no_copy {
0222         T& my_value;
0223     public:
0224         destroyer( T& value ) : my_value(value) {}
0225         ~destroyer() {my_value.~T();}
0226     };
0227 
0228     T& get_ref( page& p, size_t index ) {
0229         __TBB_ASSERT( index<items_per_page, NULL );
0230         return (&static_cast<padded_page*>(static_cast<void*>(&p))->last)[index];
0231     }
0232 
0233     virtual void copy_item( page& dst, size_t index, const void* src ) __TBB_override {
0234         new( &get_ref(dst,index) ) T(*static_cast<const T*>(src));
0235     }
0236 
0237 #if __TBB_CPP11_RVALUE_REF_PRESENT
0238     virtual void move_item( page& dst, size_t index, const void* src ) __TBB_override {
0239         new( &get_ref(dst,index) ) T( std::move(*static_cast<T*>(const_cast<void*>(src))) );
0240     }
0241 #else
0242     virtual void move_item( page&, size_t, const void* ) __TBB_override {
0243         __TBB_ASSERT( false, "Unreachable code" );
0244     }
0245 #endif
0246 
0247     virtual void copy_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) __TBB_override {
0248         new( &get_ref(dst,dindex) ) T( get_ref( const_cast<page&>(src), sindex ) );
0249     }
0250 
0251 #if __TBB_CPP11_RVALUE_REF_PRESENT
0252     virtual void move_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) __TBB_override {
0253         new( &get_ref(dst,dindex) ) T( std::move(get_ref( const_cast<page&>(src), sindex )) );
0254     }
0255 #else
0256     virtual void move_page_item( page&, size_t, const page&, size_t ) __TBB_override {
0257         __TBB_ASSERT( false, "Unreachable code" );
0258     }
0259 #endif
0260 
0261     virtual void assign_and_destroy_item( void* dst, page& src, size_t index ) __TBB_override {
0262         T& from = get_ref(src,index);
0263         destroyer d(from);
0264         *static_cast<T*>(dst) = tbb::internal::move( from );
0265     }
0266 
0267     virtual page *allocate_page() __TBB_override {
0268         size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
0269         page *p = reinterpret_cast<page*>(my_allocator.allocate( n ));
0270         if( !p )
0271             internal::throw_exception(internal::eid_bad_alloc);
0272         return p;
0273     }
0274 
0275     virtual void deallocate_page( page *p ) __TBB_override {
0276         size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
0277         my_allocator.deallocate( reinterpret_cast<char*>(p), n );
0278     }
0279 
0280 public:
0281     //! Element type in the queue.
0282     typedef T value_type;
0283 
0284     //! Allocator type
0285     typedef A allocator_type;
0286 
0287     //! Reference type
0288     typedef T& reference;
0289 
0290     //! Const reference type
0291     typedef const T& const_reference;
0292 
0293     //! Integral type for representing size of the queue.
0294     /** Note that the size_type is a signed integral type.
0295         This is because the size can be negative if there are pending pops without corresponding pushes. */
0296     typedef std::ptrdiff_t size_type;
0297 
0298     //! Difference type for iterator
0299     typedef std::ptrdiff_t difference_type;
0300 
0301     //! Construct empty queue
0302     explicit concurrent_bounded_queue(const allocator_type& a = allocator_type()) :
0303         concurrent_queue_base_v8( sizeof(T) ), my_allocator( a )
0304     {
0305     }
0306 
0307     //! Copy constructor
0308     concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a = allocator_type())
0309         : concurrent_queue_base_v8( sizeof(T) ), my_allocator( a )
0310     {
0311         assign( src );
0312     }
0313 
0314 #if __TBB_CPP11_RVALUE_REF_PRESENT
0315     //! Move constructors
0316     concurrent_bounded_queue( concurrent_bounded_queue&& src )
0317         : concurrent_queue_base_v8( sizeof(T) ), my_allocator( std::move(src.my_allocator) )
0318     {
0319         internal_swap( src );
0320     }
0321 
0322     concurrent_bounded_queue( concurrent_bounded_queue&& src, const allocator_type& a )
0323         : concurrent_queue_base_v8( sizeof(T) ), my_allocator( a )
0324     {
0325         // checking that memory allocated by one instance of allocator can be deallocated
0326         // with another
0327         if( my_allocator == src.my_allocator) {
0328             this->internal_swap( src );
0329         } else {
0330             // allocators are different => performing per-element move
0331             this->move_content( src );
0332             src.clear();
0333         }
0334     }
0335 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
0336 
0337     //! [begin,end) constructor
0338     template<typename InputIterator>
0339     concurrent_bounded_queue( InputIterator begin, InputIterator end,
0340                               const allocator_type& a = allocator_type())
0341         : concurrent_queue_base_v8( sizeof(T) ), my_allocator( a )
0342     {
0343         for( ; begin != end; ++begin )
0344             internal_push_if_not_full(&*begin);
0345     }
0346 
0347     //! Destroy queue
0348     ~concurrent_bounded_queue();
0349 
0350     //! Enqueue an item at tail of queue.
0351     void push( const T& source ) {
0352         internal_push( &source );
0353     }
0354 
0355 #if __TBB_CPP11_RVALUE_REF_PRESENT
0356     //! Move an item at tail of queue.
0357     void push( T&& source ) {
0358         internal_push_move( &source );
0359     }
0360 
0361 #if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0362     template<typename... Arguments>
0363     void emplace( Arguments&&... args ) {
0364         push( T(std::forward<Arguments>( args )...) );
0365     }
0366 #endif /* __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT */
0367 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
0368 
0369     //! Dequeue item from head of queue.
0370     /** Block until an item becomes available, and then dequeue it. */
0371     void pop( T& destination ) {
0372         internal_pop( &destination );
0373     }
0374 
0375 #if TBB_USE_EXCEPTIONS
0376     //! Abort all pending queue operations
0377     void abort() {
0378         internal_abort();
0379     }
0380 #endif
0381 
0382     //! Enqueue an item at tail of queue if queue is not already full.
0383     /** Does not wait for queue to become not full.
0384         Returns true if item is pushed; false if queue was already full. */
0385     bool try_push( const T& source ) {
0386         return internal_push_if_not_full( &source );
0387     }
0388 
0389 #if __TBB_CPP11_RVALUE_REF_PRESENT
0390     //! Move an item at tail of queue if queue is not already full.
0391     /** Does not wait for queue to become not full.
0392         Returns true if item is pushed; false if queue was already full. */
0393     bool try_push( T&& source ) {
0394         return internal_push_move_if_not_full( &source );
0395     }
0396 #if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
0397     template<typename... Arguments>
0398     bool try_emplace( Arguments&&... args ) {
0399         return try_push( T(std::forward<Arguments>( args )...) );
0400     }
0401 #endif /* __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT */
0402 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
0403 
0404     //! Attempt to dequeue an item from head of queue.
0405     /** Does not wait for item to become available.
0406         Returns true if successful; false otherwise. */
0407     bool try_pop( T& destination ) {
0408         return internal_pop_if_present( &destination );
0409     }
0410 
0411     //! Return number of pushes minus number of pops.
0412     /** Note that the result can be negative if there are pops waiting for the
0413         corresponding pushes.  The result can also exceed capacity() if there
0414         are push operations in flight. */
0415     size_type size() const {return internal_size();}
0416 
0417     //! Equivalent to size()<=0.
0418     bool empty() const {return internal_empty();}
0419 
0420     //! Maximum number of allowed elements
0421     size_type capacity() const {
0422         return my_capacity;
0423     }
0424 
0425     //! Set the capacity
0426     /** Setting the capacity to 0 causes subsequent try_push operations to always fail,
0427         and subsequent push operations to block forever. */
0428     void set_capacity( size_type new_capacity ) {
0429         internal_set_capacity( new_capacity, sizeof(T) );
0430     }
0431 
0432     //! return allocator object
0433     allocator_type get_allocator() const { return this->my_allocator; }
0434 
0435     //! clear the queue. not thread-safe.
0436     void clear() ;
0437 
0438     typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,T> iterator;
0439     typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,const T> const_iterator;
0440 
0441     //------------------------------------------------------------------------
0442     // The iterators are intended only for debugging.  They are slow and not thread safe.
0443     //------------------------------------------------------------------------
0444     iterator unsafe_begin() {return iterator(*this);}
0445     iterator unsafe_end() {return iterator();}
0446     const_iterator unsafe_begin() const {return const_iterator(*this);}
0447     const_iterator unsafe_end() const {return const_iterator();}
0448 
0449 };
0450 
0451 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
0452 // guide for concurrent_bounded_queue(InputIterator, InputIterator, ...)
0453 template<typename InputIterator,
0454          typename T = typename std::iterator_traits<InputIterator>::value_type,
0455          typename A = cache_aligned_allocator<T>
0456 > concurrent_bounded_queue(InputIterator, InputIterator, const A& = A())
0457 -> concurrent_bounded_queue<T, A>;
0458 #endif /* __TBB_CPP17_DEDUCTION_GUIDES_PRESENT */
0459 
0460 template<typename T, class A>
0461 concurrent_bounded_queue<T,A>::~concurrent_bounded_queue() {
0462     clear();
0463     internal_finish_clear();
0464 }
0465 
0466 template<typename T, class A>
0467 void concurrent_bounded_queue<T,A>::clear() {
0468     T value;
0469     while( try_pop(value) ) /*noop*/;
0470 }
0471 
0472 using strict_ppl::concurrent_queue;
0473 
0474 } // namespace tbb
0475 
0476 #include "internal/_warning_suppress_disable_notice.h"
0477 #undef __TBB_concurrent_queue_H_include_area
0478 
0479 #endif /* __TBB_concurrent_queue_H */