@@ -135,6 +135,9 @@ inline Link CLASS::top(const Link& index) const NOEXCEPT
135135 // xcode clang++16 does not support C++20 std::atomic_ref.
136136 // //const std::atomic_ref<integer> head(unsafe_byte_cast<integer>(raw));
137137 const auto & head = *pointer_cast<std::atomic<integer>>(raw);
138+
139+ // Acquire is necessary to synchronize with push release.
140+ // Relaxed would miss next updates, so acquire is optimal.
138141 return head.load (std::memory_order_acquire);
139142 }
140143 else
@@ -169,7 +172,19 @@ inline bool CLASS::push(const Link& current, bytes& next,
169172 // xcode clang++16 does not support C++20 std::atomic_ref.
170173 // //const std::atomic_ref<integer> head(unsafe_byte_cast<integer>(raw));
171174 auto & head = *pointer_cast<std::atomic<integer>>(raw);
172- next = Link (head.exchange (current, std::memory_order_acq_rel));
175+
176+ integer top = head.load (std::memory_order_acquire);
177+ do
178+ {
179+ // Compiler could order this after head.store, which would expose key
180+ // to search before next entry is linked. Thread fence imposes order.
181+ // A release fence ensures that all prior writes (like next) are
182+ // completed before any subsequent atomic store.
183+ next = Link{ top };
184+ std::atomic_thread_fence (std::memory_order_release);
185+ }
186+ while (!head.compare_exchange_weak (top, current,
187+ std::memory_order_release, std::memory_order_acquire));
173188 }
174189 else
175190 {
0 commit comments