diff options
Diffstat (limited to 'boost/lockfree/stack.hpp')
-rw-r--r-- | boost/lockfree/stack.hpp | 239 |
1 files changed, 226 insertions, 13 deletions
diff --git a/boost/lockfree/stack.hpp b/boost/lockfree/stack.hpp index 6db986c87b..23488b1ad0 100644 --- a/boost/lockfree/stack.hpp +++ b/boost/lockfree/stack.hpp @@ -9,11 +9,11 @@ #include <boost/assert.hpp> #include <boost/checked_delete.hpp> +#include <boost/core/no_exceptions_support.hpp> #include <boost/integer_traits.hpp> #include <boost/static_assert.hpp> #include <boost/tuple/tuple.hpp> -#include <boost/type_traits/has_trivial_assign.hpp> -#include <boost/type_traits/has_trivial_destructor.hpp> +#include <boost/type_traits/is_copy_constructible.hpp> #include <boost/lockfree/detail/atomic.hpp> #include <boost/lockfree/detail/copy_payload.hpp> @@ -21,6 +21,8 @@ #include <boost/lockfree/detail/parameter.hpp> #include <boost/lockfree/detail/tagged_ptr.hpp> +#include <boost/lockfree/lockfree_forward.hpp> + #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif @@ -58,22 +60,22 @@ typedef parameter::parameters<boost::parameter::optional<tag::allocator>, * \b Requirements: * - T must have a copy constructor * */ -#ifndef BOOST_DOXYGEN_INVOKED -template <typename T, - class A0 = boost::parameter::void_, - class A1 = boost::parameter::void_, - class A2 = boost::parameter::void_> +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES +template <typename T, class A0, class A1, class A2> #else -template <typename T, ...Options> +template <typename T, typename ...Options> #endif class stack { private: #ifndef BOOST_DOXYGEN_INVOKED - BOOST_STATIC_ASSERT(boost::has_trivial_assign<T>::value); - BOOST_STATIC_ASSERT(boost::has_trivial_destructor<T>::value); + BOOST_STATIC_ASSERT(boost::is_copy_constructible<T>::value); +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES typedef typename detail::stack_signature::bind<A0, A1, A2>::type bound_args; +#else + typedef typename detail::stack_signature::bind<Options...>::type bound_args; +#endif static const bool has_capacity = detail::extract_capacity<bound_args>::has_capacity; static const size_t capacity = detail::extract_capacity<bound_args>::capacity; @@ -253,7 +255,7 @@ private: node * new_top_node = end_node; end_node->next = NULL; - try { + BOOST_TRY { /* link nodes */ for (; it != end; ++it) { node * newnode = pool.template construct<Threadsafe, Bounded>(*it); @@ -262,14 +264,16 @@ private: newnode->next = new_top_node; new_top_node = newnode; } - } catch (...) { + } BOOST_CATCH (...) { for (node * current_node = new_top_node; current_node != NULL;) { node * next = current_node->next; pool.template destruct<Threadsafe>(current_node); current_node = next; } - throw; + BOOST_RETHROW; } + BOOST_CATCH_END + ret = it; return make_tuple(new_top_node, end_node); } @@ -555,6 +559,215 @@ public: return element_count; } + /** consumes all elements via a functor + * + * atomically pops all elements from the stack and applies the functor on each object + * + * \returns number of elements that are consumed + * + * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking + * */ + template <typename Functor> + size_t consume_all_atomic(Functor & f) + { + size_t element_count = 0; + tagged_node_handle old_tos = tos.load(detail::memory_order_consume); + + for (;;) { + node * old_tos_pointer = pool.get_pointer(old_tos); + if (!old_tos_pointer) + return 0; + + tagged_node_handle new_tos(typename pool_t::index_t(NULL), old_tos.get_next_tag()); + + if (tos.compare_exchange_weak(old_tos, new_tos)) + break; + } + + tagged_node_handle nodes_to_consume = old_tos; + + for(;;) { + node * node_pointer = pool.get_pointer(nodes_to_consume); + f(node_pointer->v); + element_count += 1; + + node * next_node = pool.get_pointer(node_pointer->next); + + if (!next_node) { + pool.template destruct<true>(nodes_to_consume); + break; + } + + tagged_node_handle next(pool.get_handle(next_node), nodes_to_consume.get_next_tag()); + pool.template destruct<true>(nodes_to_consume); + nodes_to_consume = next; + } + + return element_count; + } + + /// \copydoc boost::lockfree::stack::consume_all_atomic(Functor & rhs) + template <typename Functor> + size_t consume_all_atomic(Functor const & f) + { + size_t element_count = 0; + tagged_node_handle old_tos = tos.load(detail::memory_order_consume); + + for (;;) { + node * old_tos_pointer = pool.get_pointer(old_tos); + if (!old_tos_pointer) + return 0; + + tagged_node_handle new_tos(typename pool_t::index_t(NULL), old_tos.get_next_tag()); + + if (tos.compare_exchange_weak(old_tos, new_tos)) + break; + } + + tagged_node_handle nodes_to_consume = old_tos; + + for(;;) { + node * node_pointer = pool.get_pointer(nodes_to_consume); + f(node_pointer->v); + element_count += 1; + + node * next_node = pool.get_pointer(node_pointer->next); + + if (!next_node) { + pool.template destruct<true>(nodes_to_consume); + break; + } + + tagged_node_handle next(pool.get_handle(next_node), nodes_to_consume.get_next_tag()); + pool.template destruct<true>(nodes_to_consume); + nodes_to_consume = next; + } + + return element_count; + } + + /** consumes all elements via a functor + * + * atomically pops all elements from the stack and applies the functor on each object in reversed order + * + * \returns number of elements that are consumed + * + * \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking + * */ + template <typename Functor> + size_t consume_all_atomic_reversed(Functor & f) + { + size_t element_count = 0; + tagged_node_handle old_tos = tos.load(detail::memory_order_consume); + + for (;;) { + node * old_tos_pointer = pool.get_pointer(old_tos); + if (!old_tos_pointer) + return 0; + + tagged_node_handle new_tos(pool.null_handle(), old_tos.get_next_tag()); + + if (tos.compare_exchange_weak(old_tos, new_tos)) + break; + } + + tagged_node_handle nodes_to_consume = old_tos; + + node * last_node_pointer = NULL; + tagged_node_handle nodes_in_reversed_order; + for(;;) { + node * node_pointer = pool.get_pointer(nodes_to_consume); + node * next_node = pool.get_pointer(node_pointer->next); + + node_pointer->next = pool.get_handle(last_node_pointer); + last_node_pointer = node_pointer; + + if (!next_node) { + nodes_in_reversed_order = nodes_to_consume; + break; + } + + tagged_node_handle next(pool.get_handle(next_node), nodes_to_consume.get_next_tag()); + nodes_to_consume = next; + } + + for(;;) { + node * node_pointer = pool.get_pointer(nodes_in_reversed_order); + f(node_pointer->v); + element_count += 1; + + node * next_node = pool.get_pointer(node_pointer->next); + + if (!next_node) { + pool.template destruct<true>(nodes_in_reversed_order); + break; + } + + tagged_node_handle next(pool.get_handle(next_node), nodes_in_reversed_order.get_next_tag()); + pool.template destruct<true>(nodes_in_reversed_order); + nodes_in_reversed_order = next; + } + + return element_count; + } + + /// \copydoc boost::lockfree::stack::consume_all_atomic_reversed(Functor & rhs) + template <typename Functor> + size_t consume_all_atomic_reversed(Functor const & f) + { + size_t element_count = 0; + tagged_node_handle old_tos = tos.load(detail::memory_order_consume); + + for (;;) { + node * old_tos_pointer = pool.get_pointer(old_tos); + if (!old_tos_pointer) + return 0; + + tagged_node_handle new_tos(pool.null_handle(), old_tos.get_next_tag()); + + if (tos.compare_exchange_weak(old_tos, new_tos)) + break; + } + + tagged_node_handle nodes_to_consume = old_tos; + + node * last_node_pointer = NULL; + tagged_node_handle nodes_in_reversed_order; + for(;;) { + node * node_pointer = pool.get_pointer(nodes_to_consume); + node * next_node = pool.get_pointer(node_pointer->next); + + node_pointer->next = pool.get_handle(last_node_pointer); + last_node_pointer = node_pointer; + + if (!next_node) { + nodes_in_reversed_order = nodes_to_consume; + break; + } + + tagged_node_handle next(pool.get_handle(next_node), nodes_to_consume.get_next_tag()); + nodes_to_consume = next; + } + + for(;;) { + node * node_pointer = pool.get_pointer(nodes_in_reversed_order); + f(node_pointer->v); + element_count += 1; + + node * next_node = pool.get_pointer(node_pointer->next); + + if (!next_node) { + pool.template destruct<true>(nodes_in_reversed_order); + break; + } + + tagged_node_handle next(pool.get_handle(next_node), nodes_in_reversed_order.get_next_tag()); + pool.template destruct<true>(nodes_in_reversed_order); + nodes_in_reversed_order = next; + } + + return element_count; + } /** * \return true, if stack is empty. * |