3 #ifndef __CDS_INTRUSIVE_MOIR_QUEUE_H
4 #define __CDS_INTRUSIVE_MOIR_QUEUE_H
6 #include <cds/intrusive/msqueue.h>
8 namespace cds { namespace intrusive {
10 /// A variation of Michael & Scott's lock-free queue (intrusive variant)
11 /** @ingroup cds_intrusive_queue
12 This is slightly optimized Michael & Scott's queue algorithm that overloads \ref dequeue function.
15 \li [2000] Simon Doherty, Lindsay Groves, Victor Luchangco, Mark Moir
16 "Formal Verification of a practical lock-free queue algorithm"
18 Cite from this work about difference from Michael & Scott algo:
19 "Our algorithm differs from Michael and Scott
\92s [MS98] in that we test whether \p Tail points to the header
20 node only <b>after</b> \p Head has been updated, so a dequeuing process reads \p Tail only once. The dequeue in
21 [MS98] performs this test before checking whether the next pointer in the dummy node is null, which
22 means that it reads \p Tail every time a dequeuing process loops. Under high load, when operations retry
23 frequently, our modification will reduce the number of accesses to global memory. This modification, however,
24 introduces the possibility of \p Head and \p Tail
\93crossing
\94."
26 Type of node: \ref single_link::node
28 Explanation of template arguments see intrusive::MSQueue.
32 #include <cds/intrusive/moir_queue.h>
33 #include <cds/gc/hp.h>
35 namespace ci = cds::inrtusive;
36 typedef cds::gc::HP hp_gc;
38 // MoirQueue with Hazard Pointer garbage collector, base hook + item disposer:
39 struct Foo: public ci::single_link::node< hp_gc >
45 // Disposer for Foo struct just deletes the object passed in
47 void operator()( Foo * p )
53 typedef ci::MoirQueue<
57 ci::single_link::base_hook< ci::opt::gc<hp_gc> >
59 ,ci::opt::disposer< fooDisposer >
62 // MoirQueue with Hazard Pointer garbage collector,
63 // member hook + item disposer + item counter,
64 // without alignment of internal queue data:
69 ci::single_link::node< hp_gc > hMember;
72 typedef ci::MoirQueue<
76 ci::single_link::member_hook<
77 offsetof(Bar, hMember)
81 ,ci::opt::disposer< fooDisposer >
82 ,cds::opt::item_counter< cds::atomicity::item_counter >
83 ,cds::opt::alignment< cds::opt::no_special_alignment >
88 template <typename GC, typename T, CDS_DECL_OPTIONS9>
89 class MoirQueue: public MSQueue< GC, T, CDS_OPTIONS9 >
92 typedef MSQueue< GC, T, CDS_OPTIONS9 > base_class;
93 typedef typename base_class::node_type node_type;
98 typedef typename base_class::value_type value_type;
99 typedef typename base_class::back_off back_off;
100 typedef typename base_class::gc gc;
101 typedef typename base_class::node_traits node_traits;
102 typedef typename base_class::memory_model memory_model;
105 /// Rebind template arguments
106 template <typename GC2, typename T2, CDS_DECL_OTHER_OPTIONS9>
108 typedef MoirQueue< GC2, T2, CDS_OTHER_OPTIONS9> other ; ///< Rebinding result
113 typedef typename base_class::dequeue_result dequeue_result;
114 typedef typename base_class::node_to_value node_to_value;
116 bool do_dequeue( dequeue_result& res )
123 h = res.guards.protect( 0, base_class::m_pHead, node_to_value() );
124 pNext = res.guards.protect( 1, h->m_pNext, node_to_value() );
126 if ( pNext == nullptr )
127 return false ; // queue is empty
129 if ( base_class::m_pHead.compare_exchange_strong( h, pNext, memory_model::memory_order_release, atomics::memory_order_relaxed )) {
130 node_type * t = base_class::m_pTail.load(memory_model::memory_order_acquire);
132 base_class::m_pTail.compare_exchange_strong( t, pNext, memory_model::memory_order_release, atomics::memory_order_relaxed );
136 base_class::m_Stat.onDequeueRace();
140 --base_class::m_ItemCounter;
141 base_class::m_Stat.onDequeue();
150 /// Dequeues a value from the queue
151 /** @anchor cds_intrusive_MoirQueue_dequeue
152 See warning about item disposing in \ref MSQueue::dequeue.
154 value_type * dequeue()
157 if ( do_dequeue( res )) {
158 base_class::dispose_result( res );
159 return node_traits::to_value_ptr( *res.pNext );
164 /// Synonym for \ref cds_intrusive_MoirQueue_dequeue "dequeue" function
171 }} // namespace cds::intrusive
173 #endif // #ifndef __CDS_INTRUSIVE_MOIR_QUEUE_H