2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef CDSLIB_CONTAINER_MSQUEUE_H
32 #define CDSLIB_CONTAINER_MSQUEUE_H
35 #include <cds/intrusive/msqueue.h>
36 #include <cds/container/details/base.h>
38 namespace cds { namespace container {
40 /// MSQueue related definitions
41 /** @ingroup cds_nonintrusive_helper
44 /// Internal statistics
45 template <typename Counter = cds::intrusive::msqueue::stat<>::counter_type >
46 using stat = cds::intrusive::msqueue::stat< Counter >;
48 /// Dummy internal statistics
49 typedef cds::intrusive::msqueue::empty_stat empty_stat;
51 /// MSQueue default type traits
55 typedef CDS_DEFAULT_ALLOCATOR allocator;
58 typedef cds::backoff::empty back_off;
60 /// Item counting feature; by default, disabled. Use \p cds::atomicity::item_counter to enable item counting
61 typedef atomicity::empty_item_counter item_counter;
63 /// Internal statistics (by default, disabled)
65 Possible option value are: \p msqueue::stat, \p msqueue::empty_stat (the default),
66 user-provided class that supports \p %msqueue::stat interface.
68 typedef msqueue::empty_stat stat;
70 /// C++ memory ordering model
72 Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
73 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
75 typedef opt::v::relaxed_ordering memory_model;
77 /// Padding for internal critical atomic data. Default is \p opt::cache_line_padding
78 enum { padding = opt::cache_line_padding };
81 /// Metafunction converting option list to \p msqueue::traits
83 Supported \p Options are:
84 - \p opt::allocator - allocator (like \p std::allocator) used for allocating queue nodes. Default is \ref CDS_DEFAULT_ALLOCATOR
85 - \p opt::back_off - back-off strategy used, default is \p cds::backoff::empty.
86 - \p opt::item_counter - the type of item counting feature. Default is \p cds::atomicity::empty_item_counter (item counting disabled)
87 To enable item counting use \p cds::atomicity::item_counter
88 - \p opt::stat - the type to gather internal statistics.
89 Possible statistics types are: \p msqueue::stat, \p msqueue::empty_stat, user-provided class that supports \p %msqueue::stat interface.
90 Default is \p %msqueue::empty_stat.
91 - \p opt::padding - padding for internal critical atomic data. Default is \p opt::cache_line_padding
92 - \p opt::memory_model - C++ memory ordering model. Can be \p opt::v::relaxed_ordering (relaxed memory model, the default)
93 or \p opt::v::sequential_consistent (sequentially consisnent memory model).
95 Example: declare \p %MSQueue with item counting and internal statistics
97 typedef cds::container::MSQueue< cds::gc::HP, Foo,
98 typename cds::container::msqueue::make_traits<
99 cds::opt::item_counter< cds::atomicity::item_counter >,
100 cds::opt::stat< cds::container::msqueue::stat<> >
105 template <typename... Options>
107 # ifdef CDS_DOXYGEN_INVOKED
108 typedef implementation_defined type; ///< Metafunction result
110 typedef typename cds::opt::make_options<
111 typename cds::opt::find_type_traits< traits, Options... >::type
116 } // namespace msqueue
120 template <typename GC, typename T, typename Traits>
124 typedef T value_type;
125 typedef Traits traits;
127 struct node_type : public intrusive::msqueue::node< gc >
131 node_type( value_type const& val )
135 template <typename... Args>
136 node_type( Args&&... args )
137 : m_value( std::forward<Args>( args )... )
141 typedef typename traits::allocator::template rebind<node_type>::other allocator_type;
142 typedef cds::details::Allocator< node_type, allocator_type > cxx_allocator;
144 struct node_deallocator
146 void operator ()( node_type * pNode )
148 cxx_allocator().Delete( pNode );
152 struct intrusive_traits : public traits
154 typedef cds::intrusive::msqueue::base_hook< cds::opt::gc<gc> > hook;
155 typedef node_deallocator disposer;
156 static CDS_CONSTEXPR const cds::intrusive::opt::link_check_type link_checker = cds::intrusive::msqueue::traits::link_checker;
159 typedef intrusive::MSQueue< gc, node_type, intrusive_traits > type;
164 /// Michael & Scott lock-free queue
165 /** @ingroup cds_nonintrusive_queue
166 It is non-intrusive version of Michael & Scott's queue algorithm based on intrusive implementation
167 \p cds::intrusive::MSQueue.
170 - \p GC - garbage collector type: \p gc::HP, \p gc::DHP
171 - \p T is a type stored in the queue.
172 - \p Traits - queue traits, default is \p msqueue::traits. You can use \p msqueue::make_traits
173 metafunction to make your traits or just derive your traits from \p %msqueue::traits:
175 struct myTraits: public cds::container::msqueue::traits {
176 typedef cds::intrusive::msqueue::stat<> stat;
177 typedef cds::atomicity::item_counter item_counter;
179 typedef cds::container::MSQueue< cds::gc::HP, Foo, myTraits > myQueue;
181 // Equivalent make_traits example:
182 typedef cds::container::MSQueue< cds::gc::HP, Foo,
183 typename cds::container::msqueue::make_traits<
184 cds::opt::stat< cds::container::msqueue::stat<> >,
185 cds::opt::item_counter< cds::atomicity::item_counter >
190 template <typename GC, typename T, typename Traits = cds::container::msqueue::traits>
192 #ifdef CDS_DOXYGEN_INVOKED
193 private intrusive::MSQueue< GC, cds::intrusive::msqueue::node< T >, Traits >
195 private details::make_msqueue< GC, T, Traits >::type
199 typedef details::make_msqueue< GC, T, Traits > maker;
200 typedef typename maker::type base_class;
204 /// Rebind template arguments
205 template <typename GC2, typename T2, typename Traits2>
207 typedef MSQueue< GC2, T2, Traits2> other ; ///< Rebinding result
211 typedef T value_type; ///< Value type stored in the queue
212 typedef Traits traits; ///< Queue traits
214 typedef typename base_class::gc gc; ///< Garbage collector used
215 typedef typename base_class::back_off back_off; ///< Back-off strategy used
216 typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
217 typedef typename base_class::item_counter item_counter; ///< Item counting policy used
218 typedef typename base_class::stat stat; ///< Internal statistics policy used
219 typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
223 typedef typename maker::node_type node_type; ///< queue node type (derived from \p intrusive::msqueue::node)
225 typedef typename maker::cxx_allocator cxx_allocator;
226 typedef typename maker::node_deallocator node_deallocator; // deallocate node
227 typedef typename base_class::node_traits node_traits;
232 static node_type * alloc_node()
234 return cxx_allocator().New();
236 static node_type * alloc_node( value_type const& val )
238 return cxx_allocator().New( val );
240 template <typename... Args>
241 static node_type * alloc_node_move( Args&&... args )
243 return cxx_allocator().MoveNew( std::forward<Args>( args )... );
245 static void free_node( node_type * p )
247 node_deallocator()( p );
250 struct node_disposer {
251 void operator()( node_type * pNode )
256 typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
260 /// Initializes empty queue
264 /// Destructor clears the queue
268 /// Enqueues \p val value into the queue.
270 The function makes queue node in dynamic memory calling copy constructor for \p val
271 and then it calls intrusive::MSQueue::enqueue.
272 Returns \p true if success, \p false otherwise.
274 bool enqueue( value_type const& val )
276 scoped_node_ptr p( alloc_node(val) );
277 if ( base_class::enqueue( *p ) ) {
284 /// Enqueues data to the queue using a functor
286 \p Func is a functor called to create node.
287 The functor \p f takes one argument - a reference to a new node of type \ref value_type :
289 cds::container::MSQueue< cds::gc::HP, Foo > myQueue;
291 myQueue.enqueue_with( [&bar]( Foo& dest ) { dest = bar; } );
294 template <typename Func>
295 bool enqueue_with( Func f )
297 scoped_node_ptr p( alloc_node() );
299 if ( base_class::enqueue( *p )) {
306 /// Enqueues data of type \ref value_type constructed from <tt>std::forward<Args>(args)...</tt>
307 template <typename... Args>
308 bool emplace( Args&&... args )
310 scoped_node_ptr p( alloc_node_move( std::forward<Args>( args )... ) );
311 if ( base_class::enqueue( *p ) ) {
318 /// Synonym for \p enqueue() function
319 bool push( value_type const& val )
321 return enqueue( val );
324 /// Synonym for \p enqueue_with() function
325 template <typename Func>
326 bool push_with( Func f )
328 return enqueue_with( f );
331 /// Dequeues a value from the queue
333 If queue is not empty, the function returns \p true, \p dest contains copy of
334 dequeued value. The assignment operator for type \ref value_type is invoked.
335 If queue is empty, the function returns \p false, \p dest is unchanged.
337 bool dequeue( value_type& dest )
339 return dequeue_with( [&dest]( value_type& src ) { dest = src; } );
342 /// Dequeues a value using a functor
344 \p Func is a functor called to copy dequeued value.
345 The functor takes one argument - a reference to removed node:
347 cds:container::MSQueue< cds::gc::HP, Foo > myQueue;
349 myQueue.dequeue_with( [&bar]( Foo& src ) { bar = std::move( src );});
351 The functor is called only if the queue is not empty.
353 template <typename Func>
354 bool dequeue_with( Func f )
356 typename base_class::dequeue_result res;
357 if ( base_class::do_dequeue( res )) {
358 f( node_traits::to_value_ptr( *res.pNext )->m_value );
359 base_class::dispose_result( res );
365 /// Synonym for \p dequeue() function
366 bool pop( value_type& dest )
368 return dequeue( dest );
371 /// Synonym for \p dequeue_with() function
372 template <typename Func>
373 bool pop_with( Func f )
375 return dequeue_with( f );
380 The function repeatedly calls \ref dequeue until it returns \p nullptr.
387 /// Checks if the queue is empty
390 return base_class::empty();
393 /// Returns queue's item count (see \ref intrusive::MSQueue::size for explanation)
394 /** \copydetails cds::intrusive::MSQueue::size()
398 return base_class::size();
401 /// Returns reference to internal statistics
402 const stat& statistics() const
404 return base_class::statistics();
408 }} // namespace cds::container
410 #endif // #ifndef CDSLIB_CONTAINER_MSQUEUE_H