6 #ifndef XENIUM_MICHAEL_SCOTT_QUEUE_HPP
7 #define XENIUM_MICHAEL_SCOTT_QUEUE_HPP
9 #include <xenium/acquire_guard.hpp>
10 #include <xenium/backoff.hpp>
11 #include <xenium/marked_ptr.hpp>
12 #include <xenium/parameter.hpp>
13 #include <xenium/policy.hpp>
17 #pragma warning(disable : 4324) // structure was padded due to alignment specifier
37 template <
class T,
class... Policies>
41 using reclaimer = parameter::type_param_t<
policy::reclaimer, parameter::nil, Policies...>;
44 template <
class... NewPolicies>
47 static_assert(parameter::is_set<reclaimer>::value,
"reclaimer policy must be specified");
71 [[nodiscard]]
bool try_pop(T& result);
76 using concurrent_ptr =
typename reclaimer::template concurrent_ptr<node, 0>;
77 using marked_ptr =
typename concurrent_ptr::marked_ptr;
78 using guard_ptr =
typename concurrent_ptr::guard_ptr;
80 struct node : reclaimer::template enable_concurrent_ptr<node> {
82 explicit node(T&& v) : _value(std::move(v)) {}
88 alignas(64) concurrent_ptr _head;
89 alignas(64) concurrent_ptr _tail;
92 template <
class T,
class... Policies>
95 _head.store(n, std::memory_order_relaxed);
96 _tail.store(n, std::memory_order_relaxed);
99 template <
class T,
class... Policies>
100 michael_scott_queue<T, Policies...>::~michael_scott_queue() {
102 auto n = _head.load(std::memory_order_acquire);
105 auto next = n->_next.load(std::memory_order_acquire);
111 template <
class T,
class... Policies>
113 node* n =
new node(std::move(value));
121 t.acquire(_tail, std::memory_order_acquire);
125 auto next = t->_next.load(std::memory_order_acquire);
126 if (next.get() !=
nullptr) {
127 marked_ptr expected(t.get());
129 _tail.compare_exchange_weak(expected, next, std::memory_order_release, std::memory_order_relaxed);
136 if (t->_next.compare_exchange_weak(
null, n, std::memory_order_release, std::memory_order_relaxed)) {
144 marked_ptr expected = t.get();
146 _tail.compare_exchange_strong(expected, n, std::memory_order_release, std::memory_order_relaxed);
149 template <
class T,
class... Policies>
157 h.acquire(_head, std::memory_order_acquire);
161 auto next = acquire_guard(h->_next, std::memory_order_acquire);
162 if (_head.load(std::memory_order_relaxed).get() != h.get()) {
168 if (next.get() ==
nullptr) {
172 marked_ptr t = _tail.load(std::memory_order_relaxed);
175 if (h.get() == t.get()) {
177 _tail.compare_exchange_weak(t, next, std::memory_order_release, std::memory_order_relaxed);
182 marked_ptr expected(h.get());
184 if (_head.compare_exchange_weak(expected, next, std::memory_order_release, std::memory_order_relaxed)) {
186 result = std::move(next->_value);