3 #ifndef __CDS_CONTAINER_TSIGAS_CYCLE_QUEUE_H
4 #define __CDS_CONTAINER_TSIGAS_CYCLE_QUEUE_H
7 #include <cds/intrusive/tsigas_cycle_queue.h>
8 #include <cds/container/details/base.h>
10 namespace cds { namespace container {
12 /// TsigasCycleQueue related definitions
13 /** @ingroup cds_nonintrusive_helper
15 namespace tsigas_queue {
17 /// TsigasCycleQueue default traits
20 /// Buffer type for cyclic array
22 The type of element for the buffer is not important: the queue rebinds
23 buffer for required type via \p rebind metafunction.
25 For \p TsigasCycleQueue queue the buffer size should have power-of-2 size.
27 typedef cds::opt::v::dynamic_buffer< void * > buffer;
30 typedef CDS_DEFAULT_ALLOCATOR allocator;
33 typedef cds::backoff::empty back_off;
35 /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
36 typedef atomicity::empty_item_counter item_counter;
38 /// C++ memory ordering model
40 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
41 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
43 typedef opt::v::relaxed_ordering memory_model;
45 /// Alignment for internal queue data. Default is \p opt::cache_line_alignment
46 enum { alignment = opt::cache_line_alignment };
49 /// Metafunction converting option list to \p tsigas_queue::traits
51 Supported \p Options are:
52 - \p opt::buffer - the buffer type for internal cyclic array. Possible types are:
53 \p opt::v::dynamic_buffer (the default), \p opt::v::static_buffer. The type of
54 element in the buffer is not important: it will be changed via \p rebind metafunction.
55 - \p opt::allocator - allocator (like \p std::allocator) used for allocating queue items. Default is \ref CDS_DEFAULT_ALLOCATOR
56 - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty.
57 - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled)
58 To enable item counting use \p cds::atomicity::item_counter
59 - \p opt::alignment - the alignment for internal queue data. Default is \p opt::cache_line_alignment
60 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
61 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
63 Example: declare \p %TsigasCycleQueue with item counting and static iternal buffer of size 1024:
65 typedef cds::container::TsigasCycleQueue< Foo,
66 typename cds::container::tsigas_queue::make_traits<
67 cds::opt::buffer< cds::opt::v::static_buffer< void *, 1024 >,
68 cds::opt::item_counte< cds::atomicity::item_counter >
73 template <typename... Options>
75 # ifdef CDS_DOXYGEN_INVOKED
76 typedef implementation_defined type; ///< Metafunction result
78 typedef typename cds::opt::make_options<
79 typename cds::opt::find_type_traits< traits, Options... >::type
85 } // namespace tsigas_queue
89 template <typename T, typename Traits>
90 struct make_tsigas_cycle_queue
93 typedef Traits traits;
95 typedef typename traits::allocator::template rebind<value_type>::other allocator_type;
96 typedef cds::details::Allocator< value_type, allocator_type > cxx_allocator;
98 struct node_deallocator
100 void operator ()( value_type * pNode )
102 cxx_allocator().Delete( pNode );
105 typedef node_deallocator node_disposer;
107 struct intrusive_traits: public traits
109 typedef node_deallocator disposer;
112 typedef intrusive::TsigasCycleQueue< value_type, intrusive_traits > type;
117 /// Non-blocking cyclic bounded queue
118 /** @ingroup cds_nonintrusive_queue
119 It is non-intrusive implementation of Tsigas & Zhang cyclic queue based on \p intrusive::TsigasCycleQueue.
122 - [2000] Philippas Tsigas, Yi Zhang "A Simple, Fast and Scalable Non-Blocking Concurrent FIFO Queue
123 for Shared Memory Multiprocessor Systems"
126 - \p T is a type stored in the queue.
127 - \p Traits - queue traits, default is \p tsigas_queue::traits. You can use \p tsigas_queue::make_traits
128 metafunction to make your traits or just derive your traits from \p %tsigas_queue::traits:
130 struct myTraits: public cds::container::tsigas_queue::traits {
131 typedef cds::atomicity::item_counter item_counter;
133 typedef cds::container::TsigasCycleQueue< Foo, myTraits > myQueue;
135 // Equivalent make_traits example:
136 typedef cds::container::TsigasCycleQueue< cds::gc::HP, Foo,
137 typename cds::container::tsigas_queue::make_traits<
138 cds::opt::item_counter< cds::atomicity::item_counter >
145 #include <cds/container/tsigas_cycle_queue.h>
151 // Queue of Foo, capacity is 1024, statically allocated buffer:
152 typedef cds::container::TsigasCycleQueue< Foo,
153 typename cds::container::tsigas_queue::make_traits<
154 cds::opt::buffer< cds::opt::v::static_buffer< Foo, 1024 > >
157 static_queue stQueue;
159 // Queue of Foo, capacity is 1024, dynamically allocated buffer:
160 typedef cds::container::TsigasCycleQueue< Foo
161 typename cds::container::tsigas_queue::make_traits<
162 cds::opt::buffer< cds::opt::v::dynamic_buffer< Foo > >
165 dynamic_queue dynQueue( 1024 );
168 template <typename T, typename Traits = tsigas_queue::traits>
169 class TsigasCycleQueue:
170 #ifdef CDS_DOXYGEN_INVOKED
171 intrusive::TsigasCycleQueue< T, Traits >
173 details::make_tsigas_cycle_queue< T, Traits >::type
177 typedef details::make_tsigas_cycle_queue< T, Traits > maker;
178 typedef typename maker::type base_class;
181 typedef T value_type ; ///< Value type stored in the stack
182 typedef Traits traits; ///< Queue traits
184 typedef typename traits::back_off back_off; ///< Back-off strategy used
185 typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the items
186 typedef typename traits::item_counter item_counter; ///< Item counting policy used
187 typedef typename traits::memory_model memory_model; ///< Memory ordering. See \p cds::opt::memory_model option
189 /// Rebind template arguments
190 template <typename T2, typename Traits2>
192 typedef TsigasCycleQueue< T2, Traits2> other ; ///< Rebinding result
197 typedef typename maker::cxx_allocator cxx_allocator;
198 typedef typename maker::node_deallocator node_deallocator; // deallocate node
199 typedef typename maker::node_disposer node_disposer;
204 static value_type * alloc_node()
206 return cxx_allocator().New();
208 static value_type * alloc_node( const value_type& val )
210 return cxx_allocator().New( val );
212 template <typename... Args>
213 static value_type * alloc_node_move( Args&&... args )
215 return cxx_allocator().MoveNew( std::forward<Args>( args )... );
217 static void free_node( value_type * p )
219 node_deallocator()( p );
222 struct node_disposer2 {
223 void operator()( value_type * pNode )
228 typedef std::unique_ptr< value_type, node_disposer2 > scoped_node_ptr;
232 /// Initialize empty queue of capacity \p nCapacity
234 If internal buffer type is \p cds::opt::v::static_buffer, the \p nCapacity parameter is ignored.
236 Note, the real capacity of queue is \p nCapacity - 2.
238 TsigasCycleQueue( size_t nCapacity = 0 )
239 : base_class( nCapacity )
242 /// Enqueues \p val value into the queue.
244 The function makes queue node in dynamic memory calling copy constructor for \p val
245 and then it calls \p intrusive::TsigasCycleQueue::enqueue.
247 Returns \p true if success, \p false if the queue is full.
249 bool enqueue( value_type const& val )
251 scoped_node_ptr p( alloc_node(val));
252 if ( base_class::enqueue( *p )) {
259 /// Enqueues data to the queue using a functor
261 \p Func is a functor called to create node.
262 The functor \p f takes one argument - a reference to a new node of type \ref value_type :
264 cds::container::TsigasCysleQueue< Foo > myQueue;
266 myQueue.enqueue_with( [&bar]( Foo& dest ) { dest = bar; } );
269 template <typename Func>
270 bool enqueue_with( Func f )
272 scoped_node_ptr p( alloc_node() );
274 if ( base_class::enqueue( *p )) {
281 /// Enqueues data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
282 template <typename... Args>
283 bool emplace( Args&&... args )
285 scoped_node_ptr p ( alloc_node_move( std::forward<Args>(args)...));
286 if ( base_class::enqueue( *p)) {
293 /// Synonym for template version of \p enqueue() function
294 bool push( value_type const& data )
296 return enqueue( data );
299 /// Synonym for \p enqueue_with() function
300 template <typename Func>
301 bool push_with( Func f )
303 return enqueue_with( f );
306 /// Dequeues a value using a functor
308 \p Func is a functor called to copy dequeued value.
309 The functor takes one argument - a reference to removed node:
311 cds:container::TsigasCycleQueue< Foo > myQueue;
313 myQueue.dequeue_with( [&bar]( Foo& src ) { bar = std::move( src );});
315 The functor is called only if the queue is not empty.
317 template <typename Func>
318 bool dequeue_with( Func f )
320 value_type * p = base_class::dequeue();
329 /// Dequeues a value from the queue
331 If queue is not empty, the function returns \p true, \p dest contains copy of
332 dequeued value. The assignment operator for type \ref value_type is invoked.
333 If queue is empty, the function returns \p false, \p dest is unchanged.
335 bool dequeue( value_type& dest )
337 return dequeue_with( [&dest]( value_type& src ) { dest = src; } );
340 /// Synonym for \p dequeue() function
341 bool pop( value_type& dest )
343 return dequeue( dest );
346 /// Synonym for \p dequeue_with() function
347 template <typename Func>
348 bool pop_with( Func f )
350 return dequeue_with( f );
353 /// Checks if the queue is empty
356 return base_class::empty();
361 The function repeatedly calls \p dequeue() until it returns \p nullptr.
368 /// Returns queue's item count
369 /** \copydetails cds::intrusive::TsigasCycleQueue::size()
373 return base_class::size();
376 /// Returns capacity of cyclic buffer
377 size_t capacity() const
379 return base_class::capacity();
383 }} // namespace cds::intrusive
385 #endif // #ifndef __CDS_CONTAINER_TSIGAS_CYCLE_QUEUE_H