3 #ifndef __CDS_CONTAINER_MSQUEUE_H
4 #define __CDS_CONTAINER_MSQUEUE_H
7 #include <cds/intrusive/msqueue.h>
8 #include <cds/container/details/base.h>
10 #include <cds/details/trivial_assign.h>
12 namespace cds { namespace container {
16 template <typename GC, typename T, typename... Options>
22 struct default_options {
23 typedef cds::backoff::empty back_off;
24 typedef CDS_DEFAULT_ALLOCATOR allocator;
25 typedef atomicity::empty_item_counter item_counter;
26 typedef intrusive::queue_dummy_stat stat;
27 typedef opt::v::relaxed_ordering memory_model;
28 enum { alignment = opt::cache_line_alignment };
31 typedef typename opt::make_options<
32 typename cds::opt::find_type_traits< default_options, Options... >::type
36 struct node_type: public intrusive::single_link::node< gc >
39 node_type( const value_type& val )
43 template <typename... Args>
44 node_type( Args&&... args )
45 : m_value( std::forward<Args>(args)...)
49 typedef typename options::allocator::template rebind<node_type>::other allocator_type;
50 typedef cds::details::Allocator< node_type, allocator_type > cxx_allocator;
52 struct node_deallocator
54 void operator ()( node_type * pNode )
56 cxx_allocator().Delete( pNode );
60 typedef intrusive::MSQueue< gc,
62 ,intrusive::opt::hook<
63 intrusive::single_link::base_hook< opt::gc<gc> >
65 ,opt::back_off< typename options::back_off >
66 ,intrusive::opt::disposer< node_deallocator >
67 ,opt::item_counter< typename options::item_counter >
68 ,opt::stat< typename options::stat >
69 ,opt::alignment< options::alignment >
70 ,opt::memory_model< typename options::memory_model >
76 /// Michael & Scott lock-free queue
77 /** @ingroup cds_nonintrusive_queue
78 It is non-intrusive version of Michael & Scott's queue algorithm based on intrusive implementation
82 - \p GC - garbage collector type: gc::HP, gc::HRC, gc::PTB
83 - \p T is a type stored in the queue. It should be default-constructible, copy-constructible, assignable type.
84 - \p Options - options
86 Permissible \p Options:
87 - opt::allocator - allocator (like \p std::allocator). Default is \ref CDS_DEFAULT_ALLOCATOR
88 - opt::back_off - back-off strategy used. If the option is not specified, the cds::backoff::empty is used
89 - opt::item_counter - the type of item counting feature. Default is \ref atomicity::empty_item_counter
90 - opt::stat - the type to gather internal statistics.
91 Possible option value are: intrusive::queue_stat, intrusive::queue_dummy_stat,
92 user-provided class that supports intrusive::queue_stat interface.
93 Default is \ref intrusive::queue_dummy_stat.
94 - opt::alignment - the alignment for internal queue data. Default is opt::cache_line_alignment
95 - opt::memory_model - C++ memory ordering model. Can be opt::v::relaxed_ordering (relaxed memory model, the default)
96 or opt::v::sequential_consistent (sequentially consisnent memory model).
98 template <typename GC, typename T, typename... Options>
100 #ifdef CDS_DOXYGEN_INVOKED
101 intrusive::MSQueue< GC, intrusive::single_link::node< T >, Options... >
103 details::make_msqueue< GC, T, Options... >::type
107 typedef details::make_msqueue< GC, T, Options... > options;
108 typedef typename options::type base_class;
112 /// Rebind template arguments
113 template <typename GC2, typename T2, typename... Options2>
115 typedef MSQueue< GC2, T2, Options2...> other ; ///< Rebinding result
119 typedef T value_type ; ///< Value type stored in the queue
121 typedef typename base_class::gc gc ; ///< Garbage collector used
122 typedef typename base_class::back_off back_off ; ///< Back-off strategy used
123 typedef typename options::allocator_type allocator_type ; ///< Allocator type used for allocate/deallocate the nodes
124 typedef typename base_class::item_counter item_counter ; ///< Item counting policy used
125 typedef typename base_class::stat stat ; ///< Internal statistics policy used
126 typedef typename base_class::memory_model memory_model ; ///< Memory ordering. See cds::opt::memory_model option
129 typedef typename options::node_type node_type ; ///< queue node type (derived from intrusive::single_link::node)
132 typedef typename options::cxx_allocator cxx_allocator;
133 typedef typename options::node_deallocator node_deallocator; // deallocate node
134 typedef typename base_class::node_traits node_traits;
139 static node_type * alloc_node()
141 return cxx_allocator().New();
143 static node_type * alloc_node( value_type const& val )
145 return cxx_allocator().New( val );
147 template <typename... Args>
148 static node_type * alloc_node_move( Args&&... args )
150 return cxx_allocator().MoveNew( std::forward<Args>( args )... );
152 static void free_node( node_type * p )
154 node_deallocator()( p );
157 struct node_disposer {
158 void operator()( node_type * pNode )
163 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
167 /// Initializes empty queue
171 /// Destructor clears the queue
175 /// Returns queue's item count (see \ref intrusive::MSQueue::size for explanation)
178 return base_class::size();
181 /// Returns reference to internal statistics
182 const stat& statistics() const
184 return base_class::statistics();
187 /// Enqueues \p val value into the queue.
189 The function makes queue node in dynamic memory calling copy constructor for \p val
190 and then it calls intrusive::MSQueue::enqueue.
191 Returns \p true if success, \p false otherwise.
193 bool enqueue( value_type const& val )
195 scoped_node_ptr p( alloc_node(val) );
196 if ( base_class::enqueue( *p ) ) {
203 /// Enqueues \p data to queue using copy functor
205 \p Func is a functor called to copy value \p data of type \p Type
206 which may be differ from type \ref value_type stored in the queue.
207 The functor's interface is:
210 void operator()(value_type& dest, Type const& data)
212 // // Code to copy \p data to \p dest
217 You may use \p boost:ref construction to pass functor \p f by reference.
219 <b>Requirements</b> The functor \p Func should not throw any exception.
221 template <typename Type, typename Func>
222 bool enqueue( Type const& data, Func f )
224 scoped_node_ptr p( alloc_node() );
225 unref(f)( p->m_value, data );
226 if ( base_class::enqueue( *p )) {
233 /// Dequeues a value using copy functor
235 \p Func is a functor called to copy dequeued value to \p dest of type \p Type
236 which may be differ from type \ref value_type stored in the queue.
237 The functor's interface is:
240 void operator()(Type& dest, value_type const& data)
242 // Code to copy \p data to \p dest
247 You may use \p boost:ref construction to pass functor \p f by reference.
249 <b>Requirements</b> The functor \p Func should not throw any exception.
251 template <typename Type, typename Func>
252 bool dequeue( Type& dest, Func f )
254 typename base_class::dequeue_result res;
255 if ( base_class::do_dequeue( res )) {
256 unref(f)( dest, node_traits::to_value_ptr( *res.pNext )->m_value );
258 base_class::dispose_result( res );
265 /// Dequeues a value from the queue
267 If queue is not empty, the function returns \p true, \p dest contains copy of
268 dequeued value. The assignment operator for type \ref value_type is invoked.
269 If queue is empty, the function returns \p false, \p dest is unchanged.
271 bool dequeue( value_type& dest )
273 typedef cds::details::trivial_assign<value_type, value_type> functor;
274 return dequeue( dest, functor() );
277 /// Synonym for \ref enqueue function
278 bool push( value_type const& val )
280 return enqueue( val );
283 /// Synonym for template version of \ref enqueue function
284 template <typename Type, typename Func>
285 bool push( Type const& data, Func f )
287 return enqueue( data, f );
290 /// Synonym for \ref dequeue function
291 bool pop( value_type& dest )
293 return dequeue( dest );
296 /// Synonym for template version of \ref dequeue function
297 template <typename Type, typename Func>
298 bool pop( Type& dest, Func f )
300 return dequeue( dest, f );
303 /// Enqueues data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
304 template <typename... Args>
305 bool emplace( Args&&... args )
307 scoped_node_ptr p( alloc_node_move( std::forward<Args>(args)... ) );
308 if ( base_class::enqueue( *p )) {
315 /// Checks if the queue is empty
318 return base_class::empty();
323 The function repeatedly calls \ref dequeue until it returns \p nullptr.
331 }} // namespace cds::container
333 #endif // #ifndef __CDS_CONTAINER_MSQUEUE_H