moir_queue.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. // Copyright (c) 2006-2018 Maxim Khizhinsky
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef CDSLIB_CONTAINER_MOIR_QUEUE_H
  6. #define CDSLIB_CONTAINER_MOIR_QUEUE_H
  7. #include <memory>
  8. #include <cds/container/msqueue.h>
  9. #include <cds/intrusive/moir_queue.h>
  10. namespace cds { namespace container {
  11. //@cond
  12. namespace details {
  13. template <typename GC, typename T, typename Traits>
  14. struct make_moir_queue: public cds::container::details::make_msqueue< GC, T, Traits >
  15. {
  16. typedef cds::container::details::make_msqueue< GC, T, Traits > base_class;
  17. typedef cds::intrusive::MoirQueue< GC, typename base_class::node_type, typename base_class::intrusive_traits > type;
  18. };
  19. }
  20. //@endcond
  21. /// A variation of Michael & Scott's lock-free queue
  22. /** @ingroup cds_nonintrusive_queue
  23. It is non-intrusive version of \p cds::intrusive::MoirQueue.
  24. Template arguments:
  25. - \p GC - garbage collector type: \p gc::HP, \p gc::DHP
  26. - \p T - a type stored in the queue.
  27. - \p Traits - queue traits, default is \p msqueue::traits. You can use \p msqueue::make_traits
  28. metafunction to make your traits or just derive your traits from \p %msqueue::traits:
  29. \code
  30. struct myTraits: public cds::container::msqueue::traits {
  31. typedef cds::intrusive::msqueue::stat<> stat;
  32. typedef cds::atomicity::item_counter item_counter;
  33. };
  34. typedef cds::container::MoirQueue< cds::gc::HP, Foo, myTraits > myQueue;
  35. // Equivalent make_traits example:
  36. typedef cds::container::MoirQueue< cds::gc::HP, Foo,
  37. typename cds::container::msqueue::make_traits<
  38. cds::opt::stat< cds::container::msqueue::stat<> >,
  39. cds::opt::item_counter< cds::atomicity::item_counter >
  40. >::type
  41. > myQueue;
  42. \endcode
  43. */
  44. template <typename GC, typename T, typename Traits = cds::container::msqueue::traits >
  45. class MoirQueue:
  46. #ifdef CDS_DOXYGEN_INVOKED
  47. private intrusive::MoirQueue< GC, intrusive::msqueue::node< T >, Traits >
  48. #else
  49. private details::make_moir_queue< GC, T, Traits >::type
  50. #endif
  51. {
  52. //@cond
  53. typedef details::make_moir_queue< GC, T, Traits > maker;
  54. typedef typename maker::type base_class;
  55. //@endcond
  56. public:
  57. /// Rebind template arguments
  58. template <typename GC2, typename T2, typename Traits2>
  59. struct rebind {
  60. typedef MoirQueue< GC2, T2, Traits2 > other ; ///< Rebinding result
  61. };
  62. static constexpr const size_t c_nHazardPtrCount = base_class::c_nHazardPtrCount; ///< Count of hazard pointer required for the algorithm
  63. public:
  64. typedef T value_type ; ///< Value type stored in the queue
  65. typedef typename base_class::gc gc; ///< Garbage collector
  66. typedef typename base_class::back_off back_off; ///< Back-off strategy
  67. typedef typename maker::allocator_type allocator_type; ///< Allocator type used for allocate/deallocate the nodes
  68. typedef typename base_class::item_counter item_counter; ///< Item counting policy used
  69. typedef typename base_class::stat stat; ///< Internal statistics policy used
  70. typedef typename base_class::memory_model memory_model; ///< Memory ordering. See cds::opt::memory_model option
  71. protected:
  72. //@cond
  73. typedef typename maker::node_type node_type; ///< queue node type (derived from intrusive::msqueue::node)
  74. typedef typename maker::cxx_allocator cxx_allocator;
  75. typedef typename maker::node_deallocator node_deallocator; // deallocate node
  76. typedef typename base_class::node_traits node_traits;
  77. //@endcond
  78. protected:
  79. ///@cond
  80. static node_type * alloc_node()
  81. {
  82. return cxx_allocator().New();
  83. }
  84. static node_type * alloc_node( const value_type& val )
  85. {
  86. return cxx_allocator().New( val );
  87. }
  88. template <typename... Args>
  89. static node_type * alloc_node_move( Args&&... args )
  90. {
  91. return cxx_allocator().MoveNew( std::forward<Args>( args )... );
  92. }
  93. static void free_node( node_type * p )
  94. {
  95. node_deallocator()( p );
  96. }
  97. struct node_disposer {
  98. void operator()( node_type * pNode )
  99. {
  100. free_node( pNode );
  101. }
  102. };
  103. typedef std::unique_ptr< node_type, node_disposer > scoped_node_ptr;
  104. //@endcond
  105. public:
  106. /// Initializes empty queue
  107. MoirQueue()
  108. {}
  109. /// Destructor clears the queue
  110. ~MoirQueue()
  111. {}
  112. /// Enqueues \p val value into the queue.
  113. /**
  114. The function makes queue node in dynamic memory calling copy constructor for \p val
  115. and then it calls \p intrusive::MoirQueue::enqueue.
  116. Returns \p true if success, \p false otherwise.
  117. */
  118. bool enqueue( value_type const& val )
  119. {
  120. scoped_node_ptr p( alloc_node(val));
  121. if ( base_class::enqueue( *p )) {
  122. p.release();
  123. return true;
  124. }
  125. return false;
  126. }
  127. /// Enqueues \p val value into the queue, move semantics
  128. bool enqueue( value_type&& val )
  129. {
  130. scoped_node_ptr p( alloc_node_move( std::move( val )));
  131. if ( base_class::enqueue( *p )) {
  132. p.release();
  133. return true;
  134. }
  135. return false;
  136. }
  137. /// Enqueues \p data to queue using a functor
  138. /**
  139. \p Func is a functor calling to create a new node.
  140. The functor should initialize creating node
  141. and it takes one argument - a reference to a new node of type \ref value_type :
  142. \code
  143. cds:container::MoirQueue< cds::gc::HP, Foo > myQueue;
  144. Bar bar;
  145. myQueue.enqueue_with( [&bar]( Foo& dest ) { dest = bar; } );
  146. \endcode
  147. */
  148. template <typename Func>
  149. bool enqueue_with( Func f )
  150. {
  151. scoped_node_ptr p( alloc_node());
  152. f( p->m_value );
  153. if ( base_class::enqueue( *p )) {
  154. p.release();
  155. return true;
  156. }
  157. return false;
  158. }
  159. /// Enqueues data of type \ref value_type constructed with <tt>std::forward<Args>(args)...</tt>
  160. template <typename... Args>
  161. bool emplace( Args&&... args )
  162. {
  163. scoped_node_ptr p( alloc_node_move( std::forward<Args>( args )... ));
  164. if ( base_class::enqueue( *p )) {
  165. p.release();
  166. return true;
  167. }
  168. return false;
  169. }
  170. /// Synonym for \p enqueue() function
  171. bool push( value_type const& val )
  172. {
  173. return enqueue( val );
  174. }
  175. /// Synonym for \p enqueue() function, move semantics
  176. bool push( value_type&& val )
  177. {
  178. return enqueue( std::move( val ));
  179. }
  180. /// Synonym for \p enqueue_with() function
  181. template <typename Func>
  182. bool push_with( Func f )
  183. {
  184. return enqueue_with( f );
  185. }
  186. /// Dequeues a value from the queue
  187. /**
  188. If queue is not empty, the function returns \p true, \p dest contains copy of
  189. dequeued value. The assignment operator for type \ref value_type is invoked.
  190. If queue is empty, the function returns \p false, \p dest is unchanged.
  191. */
  192. bool dequeue( value_type& dest )
  193. {
  194. return dequeue_with( [&dest]( value_type& src ) {
  195. // TSan finds a race between this read of \p src and node_type constructor
  196. // I think, it is wrong
  197. CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN;
  198. dest = std::move( src );
  199. CDS_TSAN_ANNOTATE_IGNORE_READS_END;
  200. });
  201. }
  202. /// Dequeues a value using a functor
  203. /**
  204. \p Func is a functor called to copy dequeued value.
  205. The functor takes one argument - a reference to removed node:
  206. \code
  207. cds:container::MoirQueue< cds::gc::HP, Foo > myQueue;
  208. Bar bar;
  209. myQueue.dequeue_with( [&bar]( Foo& src ) { bar = std::move( src );});
  210. \endcode
  211. The functor is called only if the queue is not empty.
  212. */
  213. template <typename Func>
  214. bool dequeue_with( Func f )
  215. {
  216. typename base_class::dequeue_result res;
  217. if ( base_class::do_dequeue( res )) {
  218. f( node_traits::to_value_ptr( *res.pNext )->m_value );
  219. base_class::dispose_result( res );
  220. return true;
  221. }
  222. return false;
  223. }
  224. /// Synonym for \p dequeue() function
  225. bool pop( value_type& dest )
  226. {
  227. return dequeue( dest );
  228. }
  229. /// Synonym for \p dequeue_with() function
  230. template <typename Func>
  231. bool pop_with( Func f )
  232. {
  233. return dequeue_with( f );
  234. }
  235. /// Clear the queue
  236. /**
  237. The function repeatedly calls \ref dequeue until it returns \p nullptr.
  238. The disposer defined in template \p Traits is called for each item
  239. that can be safely disposed.
  240. */
  241. void clear()
  242. {
  243. base_class::clear();
  244. }
  245. /// Checks if the queue is empty
  246. bool empty() const
  247. {
  248. return base_class::empty();
  249. }
  250. /// Returns queue's item count (see \ref intrusive::MSQueue::size for explanation)
  251. size_t size() const
  252. {
  253. return base_class::size();
  254. }
  255. /// Returns refernce to internal statistics
  256. const stat& statistics() const
  257. {
  258. return base_class::statistics();
  259. }
  260. };
  261. }} // namespace cds::container
  262. #endif // #ifndef CDSLIB_CONTAINER_MOIR_QUEUE_H