00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef __TBB_concurrent_queue_H
00022 #define __TBB_concurrent_queue_H
00023
00024 #include "tbb_stddef.h"
00025 #include "cache_aligned_allocator.h"
00026 #include "tbb_allocator.h"
00027 #include <new>
00028
00029 namespace tbb {
00030
00031 template<typename T, class A = cache_aligned_allocator<T> >
00032 class concurrent_queue;
00033
00035 namespace internal {
00036
00037 class concurrent_queue_rep;
00038 class concurrent_queue_iterator_rep;
00039 class concurrent_queue_iterator_base_v3;
00040 template<typename Container, typename Value> class concurrent_queue_iterator;
00041
00043
00045 class concurrent_queue_base_v3: no_copy {
00047 concurrent_queue_rep* my_rep;
00048
00049 friend class concurrent_queue_rep;
00050 friend struct micro_queue;
00051 friend class micro_queue_pop_finalizer;
00052 friend class concurrent_queue_iterator_rep;
00053 friend class concurrent_queue_iterator_base_v3;
00054 protected:
00056 struct page {
00057 page* next;
00058 uintptr mask;
00059 };
00060
00062 ptrdiff_t my_capacity;
00063
00065 size_t items_per_page;
00066
00068 size_t item_size;
00069
00070 private:
00071 virtual void copy_item( page& dst, size_t index, const void* src ) = 0;
00072 virtual void assign_and_destroy_item( void* dst, page& src, size_t index ) = 0;
00073 protected:
00074 concurrent_queue_base_v3( size_t item_size );
00075 virtual ~concurrent_queue_base_v3();
00076
00078 void internal_push( const void* src );
00079
00081 void internal_pop( void* dst );
00082
00084 bool internal_push_if_not_full( const void* src );
00085
00087
00088 bool internal_pop_if_present( void* dst );
00089
00091 ptrdiff_t internal_size() const;
00092
00094 void internal_set_capacity( ptrdiff_t capacity, size_t element_size );
00095
00097 virtual page *allocate_page() = 0;
00098
00100 virtual void deallocate_page( page *p ) = 0;
00101
00103 void internal_finish_clear() ;
00104
00106 void internal_throw_exception() const;
00107 };
00108
00109 typedef concurrent_queue_base_v3 concurrent_queue_base ;
00110
00112
00113 class concurrent_queue_iterator_base_v3 {
00115
00116 concurrent_queue_iterator_rep* my_rep;
00117
00118 template<typename C, typename T, typename U>
00119 friend bool operator==( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j );
00120
00121 template<typename C, typename T, typename U>
00122 friend bool operator!=( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j );
00123 protected:
00125 mutable void* my_item;
00126
00128 concurrent_queue_iterator_base_v3() : my_rep(NULL), my_item(NULL) {}
00129
00131 concurrent_queue_iterator_base_v3( const concurrent_queue_iterator_base_v3& i ) : my_rep(NULL), my_item(NULL) {
00132 assign(i);
00133 }
00134
00136 concurrent_queue_iterator_base_v3( const concurrent_queue_base& queue );
00137
00139 void assign( const concurrent_queue_iterator_base_v3& i );
00140
00142 void advance();
00143
00145 ~concurrent_queue_iterator_base_v3();
00146 };
00147
00148 typedef concurrent_queue_iterator_base_v3 concurrent_queue_iterator_base;
00149
00151
00153 template<typename Container, typename Value>
00154 class concurrent_queue_iterator: public concurrent_queue_iterator_base_v3 {
00155 #if !defined(_MSC_VER) || defined(__INTEL_COMPILER)
00156 template<typename T, class A>
00157 friend class ::tbb::concurrent_queue;
00158 #else
00159 public:
00160 #endif
00161
00162 concurrent_queue_iterator( const concurrent_queue_base& queue ) :
00163 concurrent_queue_iterator_base_v3(queue)
00164 {
00165 }
00166 public:
00167 concurrent_queue_iterator() {}
00168
00171 concurrent_queue_iterator( const concurrent_queue_iterator<Container,typename Container::value_type>& other ) :
00172 concurrent_queue_iterator_base_v3(other)
00173 {}
00174
00176 concurrent_queue_iterator& operator=( const concurrent_queue_iterator& other ) {
00177 assign(other);
00178 return *this;
00179 }
00180
00182 Value& operator*() const {
00183 return *static_cast<Value*>(my_item);
00184 }
00185
00186 Value* operator->() const {return &operator*();}
00187
00189 concurrent_queue_iterator& operator++() {
00190 advance();
00191 return *this;
00192 }
00193
00195 Value* operator++(int) {
00196 Value* result = &operator*();
00197 operator++();
00198 return result;
00199 }
00200 };
00201
00202
00203 template<typename C, typename T, typename U>
00204 bool operator==( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j ) {
00205 return i.my_item==j.my_item;
00206 }
00207
00208 template<typename C, typename T, typename U>
00209 bool operator!=( const concurrent_queue_iterator<C,T>& i, const concurrent_queue_iterator<C,U>& j ) {
00210 return i.my_item!=j.my_item;
00211 }
00212
00213 }
00214
00216
00218
00221 template<typename T, class A>
00222 class concurrent_queue: public internal::concurrent_queue_base_v3 {
00223 template<typename Container, typename Value> friend class internal::concurrent_queue_iterator;
00224
00226 typedef typename A::template rebind<char>::other page_allocator_type;
00227 page_allocator_type my_allocator;
00228
00230 class destroyer {
00231 T& my_value;
00232 public:
00233 destroyer( T& value ) : my_value(value) {}
00234 ~destroyer() {my_value.~T();}
00235 };
00236
00237 T& get_ref( page& page, size_t index ) {
00238 __TBB_ASSERT( index<items_per_page, NULL );
00239 return static_cast<T*>(static_cast<void*>(&page+1))[index];
00240 }
00241
00242 virtual void copy_item( page& dst, size_t index, const void* src ) {
00243 new( &get_ref(dst,index) ) T(*static_cast<const T*>(src));
00244 }
00245
00246 virtual void assign_and_destroy_item( void* dst, page& src, size_t index ) {
00247 T& from = get_ref(src,index);
00248 destroyer d(from);
00249 *static_cast<T*>(dst) = from;
00250 }
00251
00252 virtual page *allocate_page() {
00253 size_t n = sizeof(page) + items_per_page*item_size;
00254 page *p = reinterpret_cast<page*>(my_allocator.allocate( n ));
00255 if( !p ) internal_throw_exception();
00256 return p;
00257 }
00258
00259 virtual void deallocate_page( page *p ) {
00260 size_t n = sizeof(page) + items_per_page*item_size;
00261 my_allocator.deallocate( reinterpret_cast<char*>(p), n );
00262 }
00263
00264 public:
00266 typedef T value_type;
00267
00269 typedef A allocator_type;
00270
00272 typedef T& reference;
00273
00275 typedef const T& const_reference;
00276
00278
00280 typedef std::ptrdiff_t size_type;
00281
00283 typedef std::ptrdiff_t difference_type;
00284
00286 concurrent_queue(const allocator_type &a = allocator_type()) :
00287 concurrent_queue_base_v3( sizeof(T) )
00288 , my_allocator( a )
00289 {
00290 }
00291
00293 ~concurrent_queue();
00294
00296 void push( const T& source ) {
00297 internal_push( &source );
00298 }
00299
00301
00302 void pop( T& destination ) {
00303 internal_pop( &destination );
00304 }
00305
00307
00309 bool push_if_not_full( const T& source ) {
00310 return internal_push_if_not_full( &source );
00311 }
00312
00314
00316 bool pop_if_present( T& destination ) {
00317 return internal_pop_if_present( &destination );
00318 }
00319
00321
00324 size_type size() const {return internal_size();}
00325
00327 bool empty() const {return size()<=0;}
00328
00330 size_type capacity() const {
00331 return my_capacity;
00332 }
00333
00335
00337 void set_capacity( size_type capacity ) {
00338 internal_set_capacity( capacity, sizeof(T) );
00339 }
00340
00342 allocator_type get_allocator() const { return this->my_allocator; }
00343
00345 void clear() ;
00346
00347 typedef internal::concurrent_queue_iterator<concurrent_queue,T> iterator;
00348 typedef internal::concurrent_queue_iterator<concurrent_queue,const T> const_iterator;
00349
00350
00351
00352
00353 iterator begin() {return iterator(*this);}
00354 iterator end() {return iterator();}
00355 const_iterator begin() const {return const_iterator(*this);}
00356 const_iterator end() const {return const_iterator();}
00357
00358 };
00359
00360 template<typename T, class A>
00361 concurrent_queue<T,A>::~concurrent_queue() {
00362 clear();
00363 }
00364
00365 template<typename T, class A>
00366 void concurrent_queue<T,A>::clear() {
00367 while( !empty() ) {
00368 T value;
00369 internal_pop_if_present(&value);
00370 }
00371 internal_finish_clear();
00372 }
00373
00374 }
00375
00376 #endif