00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef __TBB_concurrent_queue_H
00030 #define __TBB_concurrent_queue_H
00031
00032 #include "internal/_concurrent_queue_impl.h"
00033
00034 namespace tbb {
00035
00036 namespace strict_ppl {
00037
00039
00042 template<typename T, typename A = cache_aligned_allocator<T> >
00043 class concurrent_queue: public internal::concurrent_queue_base_v3<T> {
00044 template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00045
00047 typedef typename A::template rebind<char>::other page_allocator_type;
00048 page_allocator_type my_allocator;
00049
00051 virtual void *allocate_block( size_t n ) {
00052 void *b = reinterpret_cast<void*>(my_allocator.allocate( n ));
00053 if( !b )
00054 internal::throw_exception(internal::eid_bad_alloc);
00055 return b;
00056 }
00057
00059 virtual void deallocate_block( void *b, size_t n ) {
00060 my_allocator.deallocate( reinterpret_cast<char*>(b), n );
00061 }
00062
00063 public:
00065 typedef T value_type;
00066
00068 typedef T& reference;
00069
00071 typedef const T& const_reference;
00072
00074 typedef size_t size_type;
00075
00077 typedef ptrdiff_t difference_type;
00078
00080 typedef A allocator_type;
00081
00083 explicit concurrent_queue(const allocator_type& a = allocator_type()) :
00084 my_allocator( a )
00085 {
00086 }
00087
00089 template<typename InputIterator>
00090 concurrent_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
00091 my_allocator( a )
00092 {
00093 for( ; begin != end; ++begin )
00094 this->internal_push(&*begin);
00095 }
00096
00098 concurrent_queue( const concurrent_queue& src, const allocator_type& a = allocator_type()) :
00099 internal::concurrent_queue_base_v3<T>(), my_allocator( a )
00100 {
00101 this->assign( src );
00102 }
00103
00105 ~concurrent_queue();
00106
00108 void push( const T& source ) {
00109 this->internal_push( &source );
00110 }
00111
00113
00115 bool try_pop( T& result ) {
00116 return this->internal_try_pop( &result );
00117 }
00118
00120 size_type unsafe_size() const {return this->internal_size();}
00121
00123 bool empty() const {return this->internal_empty();}
00124
00126 void clear() ;
00127
00129 allocator_type get_allocator() const { return this->my_allocator; }
00130
00131 typedef internal::concurrent_queue_iterator<concurrent_queue,T> iterator;
00132 typedef internal::concurrent_queue_iterator<concurrent_queue,const T> const_iterator;
00133
00134
00135
00136
00137 iterator unsafe_begin() {return iterator(*this);}
00138 iterator unsafe_end() {return iterator();}
00139 const_iterator unsafe_begin() const {return const_iterator(*this);}
00140 const_iterator unsafe_end() const {return const_iterator();}
00141 } ;
00142
00143 template<typename T, class A>
00144 concurrent_queue<T,A>::~concurrent_queue() {
00145 clear();
00146 this->internal_finish_clear();
00147 }
00148
00149 template<typename T, class A>
00150 void concurrent_queue<T,A>::clear() {
00151 while( !empty() ) {
00152 T value;
00153 this->internal_try_pop(&value);
00154 }
00155 }
00156
00157 }
00158
00160
00165 template<typename T, class A = cache_aligned_allocator<T> >
00166 class concurrent_bounded_queue: public internal::concurrent_queue_base_v3 {
00167 template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00168
00170 typedef typename A::template rebind<char>::other page_allocator_type;
00171 page_allocator_type my_allocator;
00172
00173 typedef typename concurrent_queue_base_v3::padded_page<T> padded_page;
00174
00176 class destroyer: internal::no_copy {
00177 T& my_value;
00178 public:
00179 destroyer( T& value ) : my_value(value) {}
00180 ~destroyer() {my_value.~T();}
00181 };
00182
00183 T& get_ref( page& p, size_t index ) {
00184 __TBB_ASSERT( index<items_per_page, NULL );
00185 return (&static_cast<padded_page*>(static_cast<void*>(&p))->last)[index];
00186 }
00187
00188 virtual void copy_item( page& dst, size_t index, const void* src ) {
00189 new( &get_ref(dst,index) ) T(*static_cast<const T*>(src));
00190 }
00191
00192 virtual void copy_page_item( page& dst, size_t dindex, const page& src, size_t sindex ) {
00193 new( &get_ref(dst,dindex) ) T( get_ref( const_cast<page&>(src), sindex ) );
00194 }
00195
00196 virtual void assign_and_destroy_item( void* dst, page& src, size_t index ) {
00197 T& from = get_ref(src,index);
00198 destroyer d(from);
00199 *static_cast<T*>(dst) = from;
00200 }
00201
00202 virtual page *allocate_page() {
00203 size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
00204 page *p = reinterpret_cast<page*>(my_allocator.allocate( n ));
00205 if( !p )
00206 internal::throw_exception(internal::eid_bad_alloc);
00207 return p;
00208 }
00209
00210 virtual void deallocate_page( page *p ) {
00211 size_t n = sizeof(padded_page) + (items_per_page-1)*sizeof(T);
00212 my_allocator.deallocate( reinterpret_cast<char*>(p), n );
00213 }
00214
00215 public:
00217 typedef T value_type;
00218
00220 typedef A allocator_type;
00221
00223 typedef T& reference;
00224
00226 typedef const T& const_reference;
00227
00229
00231 typedef std::ptrdiff_t size_type;
00232
00234 typedef std::ptrdiff_t difference_type;
00235
00237 explicit concurrent_bounded_queue(const allocator_type& a = allocator_type()) :
00238 concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
00239 {
00240 }
00241
00243 concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a = allocator_type()) :
00244 concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
00245 {
00246 assign( src );
00247 }
00248
00250 template<typename InputIterator>
00251 concurrent_bounded_queue( InputIterator begin, InputIterator end, const allocator_type& a = allocator_type()) :
00252 concurrent_queue_base_v3( sizeof(T) ), my_allocator( a )
00253 {
00254 for( ; begin != end; ++begin )
00255 internal_push_if_not_full(&*begin);
00256 }
00257
00259 ~concurrent_bounded_queue();
00260
00262 void push( const T& source ) {
00263 internal_push( &source );
00264 }
00265
00267
00268 void pop( T& destination ) {
00269 internal_pop( &destination );
00270 }
00271
00272 #if TBB_USE_EXCEPTIONS
00274 void abort() {
00275 internal_abort();
00276 }
00277 #endif
00278
00280
00282 bool try_push( const T& source ) {
00283 return internal_push_if_not_full( &source );
00284 }
00285
00287
00289 bool try_pop( T& destination ) {
00290 return internal_pop_if_present( &destination );
00291 }
00292
00294
00297 size_type size() const {return internal_size();}
00298
00300 bool empty() const {return internal_empty();}
00301
00303 size_type capacity() const {
00304 return my_capacity;
00305 }
00306
00308
00310 void set_capacity( size_type new_capacity ) {
00311 internal_set_capacity( new_capacity, sizeof(T) );
00312 }
00313
00315 allocator_type get_allocator() const { return this->my_allocator; }
00316
00318 void clear() ;
00319
00320 typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,T> iterator;
00321 typedef internal::concurrent_queue_iterator<concurrent_bounded_queue,const T> const_iterator;
00322
00323
00324
00325
00326 iterator unsafe_begin() {return iterator(*this);}
00327 iterator unsafe_end() {return iterator();}
00328 const_iterator unsafe_begin() const {return const_iterator(*this);}
00329 const_iterator unsafe_end() const {return const_iterator();}
00330
00331 };
00332
00333 template<typename T, class A>
00334 concurrent_bounded_queue<T,A>::~concurrent_bounded_queue() {
00335 clear();
00336 internal_finish_clear();
00337 }
00338
00339 template<typename T, class A>
00340 void concurrent_bounded_queue<T,A>::clear() {
00341 while( !empty() ) {
00342 T value;
00343 internal_pop_if_present(&value);
00344 }
00345 }
00346
00347 namespace deprecated {
00348
00350
00355 template<typename T, class A = cache_aligned_allocator<T> >
00356 class concurrent_queue: public concurrent_bounded_queue<T,A> {
00357 #if !__TBB_TEMPLATE_FRIENDS_BROKEN
00358 template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00359 #endif
00360
00361 public:
00363 explicit concurrent_queue(const A& a = A()) :
00364 concurrent_bounded_queue<T,A>( a )
00365 {
00366 }
00367
00369 concurrent_queue( const concurrent_queue& src, const A& a = A()) :
00370 concurrent_bounded_queue<T,A>( src, a )
00371 {
00372 }
00373
00375 template<typename InputIterator>
00376 concurrent_queue( InputIterator b , InputIterator e , const A& a = A()) :
00377 concurrent_bounded_queue<T,A>( b, e, a )
00378 {
00379 }
00380
00382
00384 bool push_if_not_full( const T& source ) {
00385 return this->try_push( source );
00386 }
00387
00389
00393 bool pop_if_present( T& destination ) {
00394 return this->try_pop( destination );
00395 }
00396
00397 typedef typename concurrent_bounded_queue<T,A>::iterator iterator;
00398 typedef typename concurrent_bounded_queue<T,A>::const_iterator const_iterator;
00399
00400
00401
00402
00403 iterator begin() {return this->unsafe_begin();}
00404 iterator end() {return this->unsafe_end();}
00405 const_iterator begin() const {return this->unsafe_begin();}
00406 const_iterator end() const {return this->unsafe_end();}
00407 };
00408
00409 }
00410
00411
00412 #if TBB_DEPRECATED
00413 using deprecated::concurrent_queue;
00414 #else
00415 using strict_ppl::concurrent_queue;
00416 #endif
00417
00418 }
00419
00420 #endif