summaryrefslogtreecommitdiff
path: root/boost/lockfree/stack.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/lockfree/stack.hpp')
-rw-r--r--boost/lockfree/stack.hpp239
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.
*