From 1ba2dde07e776adc5277e29adf1a350f7f4f121b Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 4 Feb 2026 14:52:30 +0800 Subject: [PATCH 1/3] stack: migrate memory order in consume to acquire --- include/boost/lockfree/detail/freelist.hpp | 12 ++++++------ include/boost/lockfree/stack.hpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/boost/lockfree/detail/freelist.hpp b/include/boost/lockfree/detail/freelist.hpp index 23752d4..7db87db 100644 --- a/include/boost/lockfree/detail/freelist.hpp +++ b/include/boost/lockfree/detail/freelist.hpp @@ -183,7 +183,7 @@ class alignas( cacheline_bytes ) freelist_stack : Alloc template < bool Bounded > T* allocate_impl( void ) { - tagged_node_ptr old_pool = pool_.load( memory_order_consume ); + tagged_node_ptr old_pool = pool_.load( memory_order_acquire ); for ( ;; ) { if ( !old_pool.get_ptr() ) { @@ -241,7 +241,7 @@ class alignas( cacheline_bytes ) freelist_stack : Alloc void deallocate_impl( T* n ) { void* node = n; - tagged_node_ptr old_pool = pool_.load( memory_order_consume ); + tagged_node_ptr old_pool = pool_.load( memory_order_acquire ); freelist_node* new_pool_ptr = reinterpret_cast< freelist_node* >( node ); for ( ;; ) { @@ -561,7 +561,7 @@ class fixed_size_freelist : NodeStorage private: index_t allocate_impl( void ) { - tagged_index old_pool = pool_.load( memory_order_consume ); + tagged_index old_pool = pool_.load( memory_order_acquire ); for ( ;; ) { index_t index = old_pool.get_index(); @@ -580,7 +580,7 @@ class fixed_size_freelist : NodeStorage index_t allocate_impl_unsafe( void ) { - tagged_index old_pool = pool_.load( memory_order_consume ); + tagged_index old_pool = pool_.load( memory_order_acquire ); index_t index = old_pool.get_index(); if ( index == null_handle() ) @@ -607,7 +607,7 @@ class fixed_size_freelist : NodeStorage void deallocate_impl( index_t index ) { freelist_node* new_pool_node = reinterpret_cast< freelist_node* >( NodeStorage::nodes() + index ); - tagged_index old_pool = pool_.load( memory_order_consume ); + tagged_index old_pool = pool_.load( memory_order_acquire ); for ( ;; ) { tagged_index new_pool( index, old_pool.get_tag() ); @@ -621,7 +621,7 @@ class fixed_size_freelist : NodeStorage void deallocate_impl_unsafe( index_t index ) { freelist_node* new_pool_node = reinterpret_cast< freelist_node* >( NodeStorage::nodes() + index ); - tagged_index old_pool = pool_.load( memory_order_consume ); + tagged_index old_pool = pool_.load( memory_order_acquire ); tagged_index new_pool( index, old_pool.get_tag() ); new_pool_node->next.set_index( old_pool.get_index() ); diff --git a/include/boost/lockfree/stack.hpp b/include/boost/lockfree/stack.hpp index 5b353d5..4489e05 100644 --- a/include/boost/lockfree/stack.hpp +++ b/include/boost/lockfree/stack.hpp @@ -642,7 +642,7 @@ class stack template < typename Functor > bool consume_one( Functor&& f ) { - tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); + tagged_node_handle old_tos = tos.load( detail::memory_order_acquire ); for ( ;; ) { node* old_tos_pointer = pool.get_pointer( old_tos ); @@ -689,7 +689,7 @@ class stack size_t consume_all_atomic( Functor&& f ) { size_t element_count = 0; - tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); + tagged_node_handle old_tos = tos.load( detail::memory_order_acquire ); for ( ;; ) { node* old_tos_pointer = pool.get_pointer( old_tos ); @@ -736,7 +736,7 @@ class stack size_t consume_all_atomic_reversed( Functor&& f ) { size_t element_count = 0; - tagged_node_handle old_tos = tos.load( detail::memory_order_consume ); + tagged_node_handle old_tos = tos.load( detail::memory_order_acquire ); for ( ;; ) { node* old_tos_pointer = pool.get_pointer( old_tos ); From 01309c83f40644c7e34ab977ef6c97e7e28d8081 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 4 Feb 2026 15:30:23 +0800 Subject: [PATCH 2/3] stack: ensure node alignment --- include/boost/lockfree/stack.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/boost/lockfree/stack.hpp b/include/boost/lockfree/stack.hpp index 4489e05..90f8dde 100644 --- a/include/boost/lockfree/stack.hpp +++ b/include/boost/lockfree/stack.hpp @@ -82,7 +82,12 @@ class stack static const bool node_based = !( has_capacity || fixed_sized ); static const bool compile_time_sized = has_capacity; - struct node + struct node; + typedef typename detail::select_tagged_handle< node, node_based >::tagged_handle_type tagged_node_handle; + + struct alignas( node_based + ? ( alignof( tagged_node_handle ) > alignof( T ) ? alignof( tagged_node_handle ) : alignof( T ) ) + : 0 ) node { node( const T& val ) : v( val ) @@ -101,7 +106,6 @@ class stack typedef typename detail::extract_allocator< bound_args, node >::type node_allocator; typedef typename detail::select_freelist< node, node_allocator, compile_time_sized, fixed_sized, capacity >::type pool_t; - typedef typename pool_t::tagged_node_handle tagged_node_handle; // check compile-time capacity static constexpr bool capacity_is_valid = has_capacity ? capacity - 1 < std::numeric_limits< std::uint16_t >::max() From 7a31e1e712f888147b96c771e868a8ec4ac81dcc Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 4 Feb 2026 18:10:59 +0800 Subject: [PATCH 3/3] stack: testing another explicit memory barrier --- include/boost/lockfree/detail/atomic.hpp | 3 +++ include/boost/lockfree/detail/freelist.hpp | 6 ++++++ include/boost/lockfree/stack.hpp | 3 +++ 3 files changed, 12 insertions(+) diff --git a/include/boost/lockfree/detail/atomic.hpp b/include/boost/lockfree/detail/atomic.hpp index ebc07d6..ebd2e46 100644 --- a/include/boost/lockfree/detail/atomic.hpp +++ b/include/boost/lockfree/detail/atomic.hpp @@ -18,12 +18,14 @@ namespace detail { #if defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC ) using boost::atomic; +using boost::atomic_thread_fence; using boost::memory_order_acquire; using boost::memory_order_consume; using boost::memory_order_relaxed; using boost::memory_order_release; #else using std::atomic; +using std::atomic_thread_fence; using std::memory_order_acquire; using std::memory_order_consume; using std::memory_order_relaxed; @@ -32,6 +34,7 @@ using std::memory_order_release; } // namespace detail using detail::atomic; +using detail::atomic_thread_fence; using detail::memory_order_acquire; using detail::memory_order_consume; using detail::memory_order_relaxed; diff --git a/include/boost/lockfree/detail/freelist.hpp b/include/boost/lockfree/detail/freelist.hpp index 7db87db..936bd64 100644 --- a/include/boost/lockfree/detail/freelist.hpp +++ b/include/boost/lockfree/detail/freelist.hpp @@ -248,6 +248,9 @@ class alignas( cacheline_bytes ) freelist_stack : Alloc tagged_node_ptr new_pool( new_pool_ptr, old_pool.get_tag() ); new_pool->next.set_ptr( old_pool.get_ptr() ); + // Ensure the write to next is visible before the CAS makes the node visible + atomic_thread_fence( memory_order_release ); + if ( pool_.compare_exchange_weak( old_pool, new_pool ) ) return; } @@ -613,6 +616,9 @@ class fixed_size_freelist : NodeStorage tagged_index new_pool( index, old_pool.get_tag() ); new_pool_node->next.set_index( old_pool.get_index() ); + // Ensure the write to next is visible before the CAS makes the node visible + atomic_thread_fence( memory_order_release ); + if ( pool_.compare_exchange_weak( old_pool, new_pool ) ) return; } diff --git a/include/boost/lockfree/stack.hpp b/include/boost/lockfree/stack.hpp index 90f8dde..13b6eb1 100644 --- a/include/boost/lockfree/stack.hpp +++ b/include/boost/lockfree/stack.hpp @@ -270,6 +270,9 @@ class stack tagged_node_handle new_tos( pool.get_handle( new_top_node ), old_tos.get_tag() ); end_node->next = pool.get_handle( old_tos ); + // Ensure the write to end_node->next is visible before the CAS makes the node visible + detail::atomic_thread_fence( detail::memory_order_release ); + if ( tos.compare_exchange_weak( old_tos, new_tos ) ) break; }