mirror of
https://github.com/boostorg/lockfree.git
synced 2026-07-21 13:23:29 +00:00
modernisation: use c++14 where possible
This commit is contained in:
+6
-6
@@ -10,6 +10,9 @@ project(boost_lockfree VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
option(BOOST_LOCKFREE_BUILD_TESTS "Build boost::lockfree tests" OFF)
|
||||
option(BOOST_LOCKFREE_USE_FILE_SET "Use FILE_SET for boost::lockfree" OFF)
|
||||
|
||||
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
add_library(boost_lockfree INTERFACE)
|
||||
add_library(Boost::lockfree ALIAS boost_lockfree)
|
||||
@@ -36,22 +39,19 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.23 AND BOOST_LOCKFREE_USE_FILE_SET)
|
||||
target_sources(boost_lockfree PUBLIC FILE_SET HEADERS FILES ${Headers} )
|
||||
endif()
|
||||
|
||||
target_compile_features(boost_lockfree INTERFACE cxx_std_14)
|
||||
set_target_properties( boost_lockfree PROPERTIES CMAKE_CXX_STANDARD_REQUIRED 14)
|
||||
|
||||
target_link_libraries(boost_lockfree
|
||||
INTERFACE
|
||||
Boost::align
|
||||
Boost::array
|
||||
Boost::assert
|
||||
Boost::atomic
|
||||
Boost::config
|
||||
Boost::core
|
||||
Boost::integer
|
||||
Boost::iterator
|
||||
Boost::mpl
|
||||
Boost::parameter
|
||||
Boost::predef
|
||||
Boost::static_assert
|
||||
Boost::tuple
|
||||
Boost::type_traits
|
||||
Boost::utility
|
||||
)
|
||||
|
||||
|
||||
+1
-4
@@ -270,10 +270,7 @@ problem is the blocking emulation of lock-free atomics, which in the current imp
|
||||
|
||||
[section Supported Platforms & Compilers]
|
||||
|
||||
_lockfree_ has been tested on the following platforms:
|
||||
|
||||
* g++ 4.4, 4.5 and 4.6, linux, x86 & x86_64
|
||||
* clang++ 3.0, linux, x86 & x86_64
|
||||
_lockfree_ requires a c++14 compliant compiler
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -7,51 +7,7 @@
|
||||
#ifndef BOOST_LOCKFREE_DETAIL_ATOMIC_HPP
|
||||
#define BOOST_LOCKFREE_DETAIL_ATOMIC_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_LOCKFREE_FORCE_STD_ATOMIC
|
||||
|
||||
# define BOOST_LOCKFREE_NO_HDR_ATOMIC
|
||||
|
||||
// MSVC supports atomic<> from version 2012 onwards.
|
||||
# if defined( BOOST_MSVC ) && ( BOOST_MSVC >= 1700 )
|
||||
# undef BOOST_LOCKFREE_NO_HDR_ATOMIC
|
||||
# endif
|
||||
|
||||
|
||||
// GCC supports atomic<> from version 4.8 onwards.
|
||||
# if ( BOOST_GCC >= 40800 ) && ( __cplusplus >= 201103L )
|
||||
# undef BOOST_LOCKFREE_NO_HDR_ATOMIC
|
||||
# endif
|
||||
|
||||
|
||||
// Apple clang is 2 mayor versions ahead, but in fact 1 minor version behind
|
||||
# ifdef BOOST_CLANG
|
||||
|
||||
# define BOOST_ATOMIC_CLANG_VERSION ( __clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__ )
|
||||
|
||||
# if defined( __apple_build_version__ ) && ( BOOST_ATOMIC_CLANG_VERSION >= 60100 ) && ( __cplusplus >= 201103L )
|
||||
# undef BOOST_LOCKFREE_NO_HDR_ATOMIC
|
||||
# endif
|
||||
|
||||
# if !defined( __apple_build_version__ ) && ( BOOST_ATOMIC_CLANG_VERSION >= 30600 ) && ( __cplusplus >= 201103L )
|
||||
# undef BOOST_LOCKFREE_NO_HDR_ATOMIC
|
||||
# endif
|
||||
|
||||
# undef BOOST_ATOMIC_CLANG_VERSION
|
||||
|
||||
# endif // BOOST_CLANG
|
||||
|
||||
// Stdlib should also be checked
|
||||
# include <boost/config.hpp>
|
||||
# if defined( BOOST_NO_CXX11_HDR_ATOMIC ) && !defined( BOOST_LOCKFREE_NO_HDR_ATOMIC )
|
||||
# define BOOST_LOCKFREE_NO_HDR_ATOMIC
|
||||
# endif
|
||||
|
||||
#endif // BOOST_LOCKFREE_FORCE_STD_ATOMIC
|
||||
|
||||
|
||||
#if defined( BOOST_LOCKFREE_NO_HDR_ATOMIC ) || defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC )
|
||||
#if defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC )
|
||||
# include <boost/atomic.hpp>
|
||||
#else
|
||||
# include <atomic>
|
||||
@@ -60,7 +16,7 @@
|
||||
namespace boost { namespace lockfree {
|
||||
namespace detail {
|
||||
|
||||
#if defined( BOOST_LOCKFREE_NO_HDR_ATOMIC ) || defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC )
|
||||
#if defined( BOOST_LOCKFREE_FORCE_BOOST_ATOMIC )
|
||||
using boost::atomic;
|
||||
using boost::memory_order_acquire;
|
||||
using boost::memory_order_consume;
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
#ifndef BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED
|
||||
#define BOOST_LOCKFREE_DETAIL_COPY_PAYLOAD_HPP_INCLUDED
|
||||
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
# pragma warning( push )
|
||||
@@ -40,36 +39,11 @@ struct copy_constructible_and_copyable
|
||||
template < typename T, typename U >
|
||||
void copy_payload( T& t, U& u )
|
||||
{
|
||||
typedef typename boost::mpl::if_< typename boost::is_convertible< T, U >::type,
|
||||
copy_convertible,
|
||||
copy_constructible_and_copyable >::type copy_type;
|
||||
static constexpr bool is_convertible = std::is_convertible< T, U >::value;
|
||||
typedef std::conditional_t< is_convertible, copy_convertible, copy_constructible_and_copyable > copy_type;
|
||||
copy_type::copy( t, u );
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
struct consume_via_copy
|
||||
{
|
||||
consume_via_copy( T& out ) :
|
||||
out_( out )
|
||||
{}
|
||||
|
||||
template < typename U >
|
||||
void operator()( U& element )
|
||||
{
|
||||
copy_payload( element, out_ );
|
||||
}
|
||||
|
||||
T& out_;
|
||||
};
|
||||
|
||||
struct consume_noop
|
||||
{
|
||||
template < typename U >
|
||||
void operator()( const U& )
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
}}} // namespace boost::lockfree::detail
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
|
||||
@@ -9,18 +9,17 @@
|
||||
#ifndef BOOST_LOCKFREE_FREELIST_HPP_INCLUDED
|
||||
#define BOOST_LOCKFREE_FREELIST_HPP_INCLUDED
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/align/align_up.hpp>
|
||||
#include <boost/align/aligned_allocator_adaptor.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/lockfree/detail/atomic.hpp>
|
||||
#include <boost/lockfree/detail/parameter.hpp>
|
||||
@@ -34,6 +33,8 @@
|
||||
|
||||
namespace boost { namespace lockfree { namespace detail {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, typename Alloc = std::allocator< T > >
|
||||
class freelist_stack : Alloc
|
||||
{
|
||||
@@ -261,22 +262,15 @@ class BOOST_ALIGNMENT( 4 ) // workaround for bugs in MSVC
|
||||
tagged_index
|
||||
{
|
||||
public:
|
||||
typedef boost::uint16_t tag_t;
|
||||
typedef boost::uint16_t index_t;
|
||||
typedef std::uint16_t tag_t;
|
||||
typedef std::uint16_t index_t;
|
||||
|
||||
/** uninitialized constructor */
|
||||
tagged_index( void ) BOOST_NOEXCEPT //: index(0), tag(0)
|
||||
tagged_index( void ) noexcept //: index(0), tag(0)
|
||||
{}
|
||||
|
||||
/** copy constructor */
|
||||
#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
tagged_index( tagged_index const& rhs ) :
|
||||
index( rhs.index ),
|
||||
tag( rhs.tag )
|
||||
{}
|
||||
#else
|
||||
tagged_index( tagged_index const& rhs ) = default;
|
||||
#endif
|
||||
|
||||
explicit tagged_index( index_t i, tag_t t = 0 ) :
|
||||
index( i ),
|
||||
@@ -330,13 +324,15 @@ protected:
|
||||
tag_t tag;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, std::size_t size >
|
||||
struct BOOST_ALIGNMENT( BOOST_LOCKFREE_CACHELINE_BYTES ) compiletime_sized_freelist_storage
|
||||
{
|
||||
// array-based freelists only support a 16bit address space.
|
||||
BOOST_STATIC_ASSERT( size < 65536 );
|
||||
|
||||
boost::array< char, size * sizeof( T ) + 64 > data;
|
||||
std::array< char, size * sizeof( T ) + 64 > data;
|
||||
|
||||
// unused ... only for API purposes
|
||||
template < typename Allocator >
|
||||
@@ -357,6 +353,8 @@ struct BOOST_ALIGNMENT( BOOST_LOCKFREE_CACHELINE_BYTES ) compiletime_sized_freel
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, typename Alloc = std::allocator< T > >
|
||||
struct runtime_sized_freelist_storage :
|
||||
boost::alignment::aligned_allocator_adaptor< Alloc, BOOST_LOCKFREE_CACHELINE_BYTES >
|
||||
@@ -393,6 +391,7 @@ struct runtime_sized_freelist_storage :
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, typename NodeStorage = runtime_sized_freelist_storage< T > >
|
||||
class fixed_size_freelist : NodeStorage
|
||||
@@ -613,26 +612,35 @@ private:
|
||||
atomic< tagged_index > pool_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, typename Alloc, bool IsCompileTimeSized, bool IsFixedSize, std::size_t Capacity >
|
||||
struct select_freelist
|
||||
{
|
||||
typedef typename mpl::if_c< IsCompileTimeSized,
|
||||
typedef std::conditional_t< IsCompileTimeSized,
|
||||
compiletime_sized_freelist_storage< T, Capacity >,
|
||||
runtime_sized_freelist_storage< T, Alloc > >::type fixed_sized_storage_type;
|
||||
runtime_sized_freelist_storage< T, Alloc > >
|
||||
fixed_sized_storage_type;
|
||||
|
||||
typedef typename mpl::if_c< IsCompileTimeSized || IsFixedSize,
|
||||
typedef std::conditional_t< IsCompileTimeSized || IsFixedSize,
|
||||
fixed_size_freelist< T, fixed_sized_storage_type >,
|
||||
freelist_stack< T, Alloc > >::type type;
|
||||
freelist_stack< T, Alloc > >
|
||||
type;
|
||||
};
|
||||
|
||||
template < typename T, typename Alloc, bool IsCompileTimeSized, bool IsFixedSize, std::size_t Capacity >
|
||||
using select_freelist_t = typename select_freelist< T, Alloc, IsCompileTimeSized, IsFixedSize, Capacity >::type;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename T, bool IsNodeBased >
|
||||
struct select_tagged_handle
|
||||
{
|
||||
typedef typename mpl::if_c< IsNodeBased, tagged_ptr< T >, tagged_index >::type tagged_handle_type;
|
||||
|
||||
typedef typename mpl::if_c< IsNodeBased, T*, typename tagged_index::index_t >::type handle_type;
|
||||
typedef std::conditional_t< IsNodeBased, tagged_ptr< T >, tagged_index > tagged_handle_type;
|
||||
typedef std::conditional_t< IsNodeBased, T*, typename tagged_index::index_t > handle_type;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
}}} // namespace boost::lockfree::detail
|
||||
|
||||
|
||||
@@ -14,61 +14,70 @@
|
||||
#include <boost/lockfree/detail/prefix.hpp>
|
||||
#include <boost/lockfree/policies.hpp>
|
||||
#include <boost/parameter/binding.hpp>
|
||||
#include <boost/parameter/parameters.hpp>
|
||||
|
||||
#include <boost/mpl/void.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace lockfree { namespace detail {
|
||||
|
||||
namespace mpl = boost::mpl;
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename bound_args, typename tag_type, typename default_ >
|
||||
using extract_arg_or_default_t = typename parameter::binding< bound_args, tag_type, default_ >::type;
|
||||
|
||||
struct no_such_parameter_t
|
||||
{};
|
||||
|
||||
template < typename bound_args, typename tag_type >
|
||||
struct has_arg
|
||||
{
|
||||
typedef typename parameter::binding< bound_args, tag_type, mpl::void_ >::type type;
|
||||
static const bool value = mpl::is_not_void_< type >::type::value;
|
||||
};
|
||||
using has_no_arg_t
|
||||
= std::is_same< extract_arg_or_default_t< bound_args, tag_type, no_such_parameter_t >, no_such_parameter_t >;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename bound_args >
|
||||
struct extract_capacity
|
||||
{
|
||||
static const bool has_capacity = has_arg< bound_args, tag::capacity >::value;
|
||||
|
||||
typedef
|
||||
typename mpl::if_c< has_capacity, typename has_arg< bound_args, tag::capacity >::type, mpl::size_t< 0 > >::type
|
||||
capacity_t;
|
||||
|
||||
static const std::size_t capacity = capacity_t::value;
|
||||
using capacity_t = extract_arg_or_default_t< bound_args, tag::capacity, std::integral_constant< size_t, 0 > >;
|
||||
using has_no_capacity_t = has_no_arg_t< bound_args, tag::capacity >;
|
||||
static constexpr std::size_t capacity = capacity_t::value;
|
||||
static constexpr bool has_capacity = !has_no_capacity_t::value;
|
||||
};
|
||||
|
||||
template < typename bound_args >
|
||||
using extract_capacity_t = typename extract_capacity< bound_args >::type;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename bound_args, typename T >
|
||||
struct extract_allocator
|
||||
{
|
||||
static const bool has_allocator = has_arg< bound_args, tag::allocator >::value;
|
||||
using default_allocator = boost::alignment::aligned_allocator< T, BOOST_LOCKFREE_CACHELINE_BYTES >;
|
||||
using allocator_t = extract_arg_or_default_t< bound_args, tag::allocator, default_allocator >;
|
||||
|
||||
typedef
|
||||
typename mpl::if_c< has_allocator,
|
||||
typename has_arg< bound_args, tag::allocator >::type,
|
||||
boost::alignment::aligned_allocator< T, BOOST_LOCKFREE_CACHELINE_BYTES > >::type allocator_arg;
|
||||
using has_no_allocator_t = has_no_arg_t< bound_args, tag::allocator >;
|
||||
static constexpr bool has_allocator = !has_no_allocator_t::value;
|
||||
|
||||
typedef typename boost::allocator_rebind< allocator_arg, T >::type type;
|
||||
typedef typename boost::allocator_rebind< allocator_t, T >::type type;
|
||||
};
|
||||
|
||||
template < typename bound_args, typename T >
|
||||
using extract_allocator_t = typename extract_allocator< bound_args, T >::type;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template < typename bound_args, bool default_ = false >
|
||||
struct extract_fixed_sized
|
||||
{
|
||||
static const bool has_fixed_sized = has_arg< bound_args, tag::fixed_sized >::value;
|
||||
using capacity_t
|
||||
= extract_arg_or_default_t< bound_args, tag::fixed_sized, std::integral_constant< bool, default_ > >;
|
||||
|
||||
typedef typename mpl::if_c< has_fixed_sized,
|
||||
typename has_arg< bound_args, tag::fixed_sized >::type,
|
||||
mpl::bool_< default_ > >::type type;
|
||||
|
||||
static const bool value = type::value;
|
||||
static constexpr bool value = capacity_t::value;
|
||||
};
|
||||
|
||||
template < typename bound_args, bool default_ = false >
|
||||
using extract_fixed_sized_t = typename extract_fixed_sized< bound_args, default_ >::type;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
}}} // namespace boost::lockfree::detail
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <cstddef> /* for std::size_t */
|
||||
#include <limits>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
namespace boost { namespace lockfree { namespace detail {
|
||||
@@ -32,17 +33,10 @@ public:
|
||||
typedef std::size_t tag_t;
|
||||
|
||||
/** uninitialized constructor */
|
||||
tagged_ptr( void ) BOOST_NOEXCEPT //: ptr(0), tag(0)
|
||||
tagged_ptr( void ) noexcept //: ptr(0), tag(0)
|
||||
{}
|
||||
|
||||
#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
tagged_ptr( tagged_ptr const& p ) :
|
||||
ptr( p.ptr ),
|
||||
tag( p.tag )
|
||||
{}
|
||||
#else
|
||||
tagged_ptr( tagged_ptr const& p ) = default;
|
||||
#endif
|
||||
|
||||
explicit tagged_ptr( T* p, tag_t t = 0 ) :
|
||||
ptr( p ),
|
||||
@@ -51,15 +45,7 @@ public:
|
||||
|
||||
/** unsafe set operation */
|
||||
/* @{ */
|
||||
#ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
tagged_ptr& operator=( tagged_ptr const& p )
|
||||
{
|
||||
set( p.ptr, p.tag );
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
tagged_ptr& operator=( tagged_ptr const& p ) = default;
|
||||
#endif
|
||||
|
||||
void set( T* p, tag_t t )
|
||||
{
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
#ifndef BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED
|
||||
#define BOOST_LOCKFREE_TAGGED_PTR_PTRCOMPRESSION_HPP_INCLUDED
|
||||
|
||||
#include <cstddef> /* for std::size_t */
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/predef.h>
|
||||
#include <boost/lockfree/detail/prefix.hpp>
|
||||
|
||||
namespace boost { namespace lockfree { namespace detail {
|
||||
|
||||
@@ -22,10 +21,10 @@ namespace boost { namespace lockfree { namespace detail {
|
||||
template < class T >
|
||||
class tagged_ptr
|
||||
{
|
||||
typedef boost::uint64_t compressed_ptr_t;
|
||||
typedef std::uint64_t compressed_ptr_t;
|
||||
|
||||
public:
|
||||
typedef boost::uint16_t tag_t;
|
||||
typedef std::uint16_t tag_t;
|
||||
|
||||
private:
|
||||
union cast_unit
|
||||
@@ -34,8 +33,8 @@ private:
|
||||
tag_t tag[ 4 ];
|
||||
};
|
||||
|
||||
static const int tag_index = 3;
|
||||
static const compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1;
|
||||
static constexpr int tag_index = 3;
|
||||
static constexpr compressed_ptr_t ptr_mask = 0xffffffffffffUL; //(1L<<48L)-1;
|
||||
|
||||
static T* extract_ptr( volatile compressed_ptr_t const& i )
|
||||
{
|
||||
@@ -59,17 +58,11 @@ private:
|
||||
|
||||
public:
|
||||
/** uninitialized constructor */
|
||||
tagged_ptr( void ) BOOST_NOEXCEPT //: ptr(0), tag(0)
|
||||
tagged_ptr( void ) noexcept //: ptr(0), tag(0)
|
||||
{}
|
||||
|
||||
/** copy constructor */
|
||||
# ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
tagged_ptr( tagged_ptr const& p ) :
|
||||
ptr( p.ptr )
|
||||
{}
|
||||
# else
|
||||
tagged_ptr( tagged_ptr const& p ) = default;
|
||||
# endif
|
||||
|
||||
explicit tagged_ptr( T* p, tag_t t = 0 ) :
|
||||
ptr( pack_ptr( p, t ) )
|
||||
@@ -77,15 +70,7 @@ public:
|
||||
|
||||
/** unsafe set operation */
|
||||
/* @{ */
|
||||
# ifdef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
tagged_ptr& operator=( tagged_ptr const& p )
|
||||
{
|
||||
ptr = p.ptr;
|
||||
return *this;
|
||||
}
|
||||
# else
|
||||
tagged_ptr& operator=( tagged_ptr const& p ) = default;
|
||||
# endif
|
||||
|
||||
void set( T* p, tag_t t )
|
||||
{
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
|
||||
# include <boost/config.hpp>
|
||||
|
||||
# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
# include <boost/parameter/aux_/void.hpp>
|
||||
# endif
|
||||
|
||||
namespace boost { namespace lockfree {
|
||||
|
||||
// policies
|
||||
@@ -34,25 +30,13 @@ struct allocator;
|
||||
|
||||
// data structures
|
||||
|
||||
# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, class A0 = boost::parameter::void_, class A1 = boost::parameter::void_, class A2 = boost::parameter::void_ >
|
||||
# else
|
||||
template < typename T, typename... Options >
|
||||
# endif
|
||||
class queue;
|
||||
|
||||
# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, class A0 = boost::parameter::void_, class A1 = boost::parameter::void_, class A2 = boost::parameter::void_ >
|
||||
# else
|
||||
template < typename T, typename... Options >
|
||||
# endif
|
||||
class stack;
|
||||
|
||||
# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, class A0 = boost::parameter::void_, class A1 = boost::parameter::void_ >
|
||||
# else
|
||||
template < typename T, typename... Options >
|
||||
# endif
|
||||
class spsc_queue;
|
||||
|
||||
}} // namespace boost::lockfree
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
#ifndef BOOST_LOCKFREE_POLICIES_HPP_INCLUDED
|
||||
#define BOOST_LOCKFREE_POLICIES_HPP_INCLUDED
|
||||
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/mpl/size_t.hpp>
|
||||
#include <boost/parameter/template_keyword.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace lockfree {
|
||||
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
@@ -36,7 +36,7 @@ struct capacity;
|
||||
* This implies that a data structure is bounded.
|
||||
* */
|
||||
template < bool IsFixedSized >
|
||||
struct fixed_sized : boost::parameter::template_keyword< tag::fixed_sized, boost::mpl::bool_< IsFixedSized > >
|
||||
struct fixed_sized : boost::parameter::template_keyword< tag::fixed_sized, std::integral_constant< bool, IsFixedSized > >
|
||||
{};
|
||||
|
||||
/** Sets the \b capacity of a data structure at compile-time.
|
||||
@@ -44,7 +44,7 @@ struct fixed_sized : boost::parameter::template_keyword< tag::fixed_sized, boost
|
||||
* This implies that a data structure is bounded and fixed-sized.
|
||||
* */
|
||||
template < size_t Size >
|
||||
struct capacity : boost::parameter::template_keyword< tag::capacity, boost::mpl::size_t< Size > >
|
||||
struct capacity : boost::parameter::template_keyword< tag::capacity, std::integral_constant< size_t, Size > >
|
||||
{};
|
||||
|
||||
/** Defines the \b allocator type of a data structure.
|
||||
|
||||
@@ -14,16 +14,15 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp> // for BOOST_LIKELY & BOOST_ALIGNMENT
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/parameter/optional.hpp>
|
||||
#include <boost/parameter/parameters.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/has_trivial_assign.hpp>
|
||||
#include <boost/type_traits/has_trivial_destructor.hpp>
|
||||
|
||||
#include <boost/lockfree/detail/atomic.hpp>
|
||||
#include <boost/lockfree/detail/copy_payload.hpp>
|
||||
#include <boost/lockfree/detail/freelist.hpp>
|
||||
#include <boost/lockfree/detail/parameter.hpp>
|
||||
#include <boost/lockfree/detail/tagged_ptr.hpp>
|
||||
|
||||
#include <boost/lockfree/lockfree_forward.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
@@ -78,35 +77,23 @@ typedef parameter::parameters< boost::parameter::optional< tag::allocator >, boo
|
||||
* - T must have a trivial destructor
|
||||
*
|
||||
* */
|
||||
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, class A0, class A1, class A2 >
|
||||
#else
|
||||
template < typename T, typename... Options >
|
||||
#endif
|
||||
class queue
|
||||
{
|
||||
private:
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
|
||||
# ifdef BOOST_HAS_TRIVIAL_DESTRUCTOR
|
||||
BOOST_STATIC_ASSERT( ( boost::has_trivial_destructor< T >::value ) );
|
||||
# endif
|
||||
BOOST_STATIC_ASSERT( ( std::is_trivially_destructible< T >::value ) );
|
||||
BOOST_STATIC_ASSERT( ( std::is_trivially_assignable< T&, T >::value ) );
|
||||
|
||||
# ifdef BOOST_HAS_TRIVIAL_ASSIGN
|
||||
BOOST_STATIC_ASSERT( ( boost::has_trivial_assign< T >::value ) );
|
||||
# endif
|
||||
|
||||
# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
typedef typename detail::queue_signature::bind< A0, A1, A2 >::type bound_args;
|
||||
# else
|
||||
typedef typename detail::queue_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 + 1; // the queue uses one dummy node
|
||||
static const bool fixed_sized = detail::extract_fixed_sized< bound_args >::value;
|
||||
static const bool node_based = !( has_capacity || fixed_sized );
|
||||
static const bool compile_time_sized = has_capacity;
|
||||
static constexpr bool has_capacity = detail::extract_capacity< bound_args >::has_capacity;
|
||||
static constexpr size_t capacity
|
||||
= detail::extract_capacity< bound_args >::capacity + 1; // the queue uses one dummy node
|
||||
static constexpr bool fixed_sized = detail::extract_fixed_sized< bound_args >::value;
|
||||
static constexpr bool node_based = !( has_capacity || fixed_sized );
|
||||
static constexpr bool compile_time_sized = has_capacity;
|
||||
|
||||
struct BOOST_ALIGNMENT( BOOST_LOCKFREE_CACHELINE_BYTES ) node
|
||||
{
|
||||
@@ -133,9 +120,8 @@ private:
|
||||
T data;
|
||||
};
|
||||
|
||||
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 detail::extract_allocator_t< bound_args, node > node_allocator;
|
||||
typedef detail::select_freelist_t< node, node_allocator, compile_time_sized, fixed_sized, capacity > pool_t;
|
||||
typedef typename pool_t::tagged_node_handle tagged_node_handle;
|
||||
typedef typename detail::select_tagged_handle< node, node_based >::handle_type handle_type;
|
||||
|
||||
@@ -155,9 +141,6 @@ private:
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_DELETED_FUNCTION( queue( queue const& ) )
|
||||
BOOST_DELETED_FUNCTION( queue& operator=( queue const& ) )
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef typename implementation_defined::allocator allocator;
|
||||
@@ -195,13 +178,12 @@ public:
|
||||
*
|
||||
* \pre Must specify a capacity<> argument
|
||||
* */
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< has_capacity > >
|
||||
explicit queue( typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) :
|
||||
head_( tagged_node_handle( 0, 0 ) ),
|
||||
tail_( tagged_node_handle( 0, 0 ) ),
|
||||
pool( alloc, capacity )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -209,14 +191,12 @@ public:
|
||||
*
|
||||
* \pre Must specify a capacity<> argument
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< has_capacity > >
|
||||
explicit queue( allocator const& alloc ) :
|
||||
head_( tagged_node_handle( 0, 0 ) ),
|
||||
tail_( tagged_node_handle( 0, 0 ) ),
|
||||
pool( alloc, capacity )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -226,14 +206,12 @@ public:
|
||||
*
|
||||
* \pre Must \b not specify a capacity<> argument
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< !has_capacity > >
|
||||
explicit queue( size_type n ) :
|
||||
head_( tagged_node_handle( 0, 0 ) ),
|
||||
tail_( tagged_node_handle( 0, 0 ) ),
|
||||
pool( node_allocator(), n + 1 )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( !has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -243,13 +221,12 @@ public:
|
||||
*
|
||||
* \pre Must \b not specify a capacity<> argument
|
||||
* */
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< !has_capacity > >
|
||||
queue( size_type n, typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) :
|
||||
head_( tagged_node_handle( 0, 0 ) ),
|
||||
tail_( tagged_node_handle( 0, 0 ) ),
|
||||
pool( alloc, n + 1 )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( !has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -259,15 +236,20 @@ public:
|
||||
*
|
||||
* \pre Must \b not specify a capacity<> argument
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< !has_capacity > >
|
||||
queue( size_type n, allocator const& alloc ) :
|
||||
head_( tagged_node_handle( 0, 0 ) ),
|
||||
tail_( tagged_node_handle( 0, 0 ) ),
|
||||
pool( alloc, n + 1 )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( !has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
queue( const queue& ) = delete;
|
||||
queue& operator=( const queue& ) = delete;
|
||||
queue( queue&& ) = delete;
|
||||
queue& operator=( queue&& ) = delete;
|
||||
|
||||
/** \copydoc boost::lockfree::stack::reserve
|
||||
* */
|
||||
void reserve( size_type n )
|
||||
@@ -286,8 +268,7 @@ public:
|
||||
* */
|
||||
~queue( void )
|
||||
{
|
||||
T dummy;
|
||||
while ( unsynchronized_pop( dummy ) ) {}
|
||||
consume_all( []( const T& ) {} );
|
||||
|
||||
pool.template destruct< false >( head_.load( memory_order_relaxed ) );
|
||||
}
|
||||
@@ -520,19 +501,7 @@ public:
|
||||
* \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking
|
||||
* */
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor& f )
|
||||
{
|
||||
T element;
|
||||
bool success = pop( element );
|
||||
if ( success )
|
||||
f( element );
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/// \copydoc boost::lockfree::queue::consume_one(Functor & rhs)
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor const& f )
|
||||
bool consume_one( Functor&& f )
|
||||
{
|
||||
T element;
|
||||
bool success = pop( element );
|
||||
@@ -551,18 +520,7 @@ public:
|
||||
* \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking
|
||||
* */
|
||||
template < typename Functor >
|
||||
size_t consume_all( Functor& f )
|
||||
{
|
||||
size_t element_count = 0;
|
||||
while ( consume_one( f ) )
|
||||
element_count += 1;
|
||||
|
||||
return element_count;
|
||||
}
|
||||
|
||||
/// \copydoc boost::lockfree::queue::consume_all(Functor & rhs)
|
||||
template < typename Functor >
|
||||
size_t consume_all( Functor const& f )
|
||||
size_t consume_all( Functor&& f )
|
||||
{
|
||||
size_t element_count = 0;
|
||||
while ( consume_one( f ) )
|
||||
@@ -574,7 +532,7 @@ public:
|
||||
private:
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
atomic< tagged_node_handle > head_;
|
||||
static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( tagged_node_handle );
|
||||
static constexpr int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( tagged_node_handle );
|
||||
char padding1[ padding_size ];
|
||||
atomic< tagged_node_handle > tail_;
|
||||
char padding2[ padding_size ];
|
||||
|
||||
@@ -12,24 +12,21 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/aligned_storage.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp> // for BOOST_LIKELY
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include <boost/core/span.hpp>
|
||||
#include <boost/parameter/optional.hpp>
|
||||
#include <boost/parameter/parameters.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <boost/type_traits/has_trivial_destructor.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
|
||||
#include <boost/lockfree/detail/atomic.hpp>
|
||||
#include <boost/lockfree/detail/copy_payload.hpp>
|
||||
#include <boost/lockfree/detail/parameter.hpp>
|
||||
#include <boost/lockfree/detail/prefix.hpp>
|
||||
|
||||
#include <boost/lockfree/lockfree_forward.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
@@ -39,22 +36,16 @@
|
||||
namespace boost { namespace lockfree {
|
||||
namespace detail {
|
||||
|
||||
typedef parameter::parameters< boost::parameter::optional< tag::capacity >, boost::parameter::optional< tag::allocator > >
|
||||
ringbuffer_signature;
|
||||
|
||||
template < typename T >
|
||||
class ringbuffer_base
|
||||
{
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
protected:
|
||||
typedef std::size_t size_t;
|
||||
static const int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( size_t );
|
||||
atomic< size_t > write_index_;
|
||||
char padding1[ padding_size ]; /* force read_index and write_index to different cache lines */
|
||||
atomic< size_t > read_index_;
|
||||
|
||||
BOOST_DELETED_FUNCTION( ringbuffer_base( ringbuffer_base const& ) )
|
||||
BOOST_DELETED_FUNCTION( ringbuffer_base& operator=( ringbuffer_base const& ) )
|
||||
typedef std::size_t size_t;
|
||||
static constexpr int padding_size = BOOST_LOCKFREE_CACHELINE_BYTES - sizeof( size_t );
|
||||
atomic< size_t > write_index_;
|
||||
char padding1[ padding_size ]; /* force read_index and write_index to different cache lines */
|
||||
atomic< size_t > read_index_;
|
||||
|
||||
protected:
|
||||
ringbuffer_base( void ) :
|
||||
@@ -138,12 +129,12 @@ protected:
|
||||
|
||||
size_t new_write_index = write_index + input_count;
|
||||
|
||||
const ConstIterator last = boost::next( begin, input_count );
|
||||
const ConstIterator last = std::next( begin, input_count );
|
||||
|
||||
if ( write_index + input_count > max_size ) {
|
||||
/* copy data in two sections */
|
||||
const size_t count0 = max_size - write_index;
|
||||
const ConstIterator midpoint = boost::next( begin, count0 );
|
||||
const ConstIterator midpoint = std::next( begin, count0 );
|
||||
|
||||
std::uninitialized_copy( begin, midpoint, internal_buffer + write_index );
|
||||
std::uninitialized_copy( midpoint, last, internal_buffer );
|
||||
@@ -160,7 +151,7 @@ protected:
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor& functor, T* buffer, size_t max_size )
|
||||
bool consume_one( Functor&& functor, T* buffer, size_t max_size )
|
||||
{
|
||||
const size_t write_index = write_index_.load( memory_order_acquire );
|
||||
const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread
|
||||
@@ -177,59 +168,7 @@ protected:
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor const& functor, T* buffer, size_t max_size )
|
||||
{
|
||||
const size_t write_index = write_index_.load( memory_order_acquire );
|
||||
const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread
|
||||
if ( empty( write_index, read_index ) )
|
||||
return false;
|
||||
|
||||
T& object_to_consume = buffer[ read_index ];
|
||||
functor( object_to_consume );
|
||||
object_to_consume.~T();
|
||||
|
||||
size_t next = next_index( read_index, max_size );
|
||||
read_index_.store( next, memory_order_release );
|
||||
return true;
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
size_t consume_all( Functor const& functor, T* internal_buffer, size_t max_size )
|
||||
{
|
||||
const size_t write_index = write_index_.load( memory_order_acquire );
|
||||
const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread
|
||||
|
||||
const size_t avail = read_available( write_index, read_index, max_size );
|
||||
|
||||
if ( avail == 0 )
|
||||
return 0;
|
||||
|
||||
const size_t output_count = avail;
|
||||
|
||||
size_t new_read_index = read_index + output_count;
|
||||
|
||||
if ( read_index + output_count > max_size ) {
|
||||
/* copy data in two sections */
|
||||
const size_t count0 = max_size - read_index;
|
||||
const size_t count1 = output_count - count0;
|
||||
|
||||
run_functor_and_delete( internal_buffer + read_index, internal_buffer + max_size, functor );
|
||||
run_functor_and_delete( internal_buffer, internal_buffer + count1, functor );
|
||||
|
||||
new_read_index -= max_size;
|
||||
} else {
|
||||
run_functor_and_delete( internal_buffer + read_index, internal_buffer + read_index + output_count, functor );
|
||||
|
||||
if ( new_read_index == max_size )
|
||||
new_read_index = 0;
|
||||
}
|
||||
|
||||
read_index_.store( new_read_index, memory_order_release );
|
||||
return output_count;
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
size_t consume_all( Functor& functor, T* internal_buffer, size_t max_size )
|
||||
size_t consume_all( Functor&& functor, T* internal_buffer, size_t max_size )
|
||||
{
|
||||
const size_t write_index = write_index_.load( memory_order_acquire );
|
||||
const size_t read_index = read_index_.load( memory_order_relaxed ); // only written from pop thread
|
||||
@@ -348,11 +287,9 @@ public:
|
||||
* */
|
||||
void reset( void )
|
||||
{
|
||||
if ( !boost::has_trivial_destructor< T >::value ) {
|
||||
if ( !std::is_trivially_destructible< T >::value ) {
|
||||
// make sure to call all destructors!
|
||||
|
||||
detail::consume_noop consume_functor;
|
||||
(void)consume_all( consume_functor );
|
||||
consume_all( []( const T& ) {} );
|
||||
} else {
|
||||
write_index_.store( 0, memory_order_relaxed );
|
||||
read_index_.store( 0, memory_order_release );
|
||||
@@ -387,7 +324,7 @@ private:
|
||||
template < class OutputIterator >
|
||||
OutputIterator copy_and_delete( T* first, T* last, OutputIterator out )
|
||||
{
|
||||
if ( boost::has_trivial_destructor< T >::value ) {
|
||||
if ( std::is_trivially_destructible< T >::value ) {
|
||||
return std::copy( first, last, out ); // will use memcpy if possible
|
||||
} else {
|
||||
for ( ; first != last; ++first, ++out ) {
|
||||
@@ -399,16 +336,7 @@ private:
|
||||
}
|
||||
|
||||
template < class Functor >
|
||||
void run_functor_and_delete( T* first, T* last, Functor& functor )
|
||||
{
|
||||
for ( ; first != last; ++first ) {
|
||||
functor( *first );
|
||||
first->~T();
|
||||
}
|
||||
}
|
||||
|
||||
template < class Functor >
|
||||
void run_functor_and_delete( T* first, T* last, Functor const& functor )
|
||||
void run_functor_and_delete( T* first, T* last, Functor&& functor )
|
||||
{
|
||||
for ( ; first != last; ++first ) {
|
||||
functor( *first );
|
||||
@@ -420,8 +348,8 @@ private:
|
||||
template < typename T, std::size_t MaxSize >
|
||||
class compile_time_sized_ringbuffer : public ringbuffer_base< T >
|
||||
{
|
||||
typedef std::size_t size_type;
|
||||
static const std::size_t max_size = MaxSize + 1;
|
||||
typedef std::size_t size_type;
|
||||
static constexpr std::size_t max_size = MaxSize + 1;
|
||||
|
||||
typedef
|
||||
typename boost::aligned_storage< max_size * sizeof( T ), boost::alignment_of< T >::value >::type storage_type;
|
||||
@@ -447,8 +375,7 @@ protected:
|
||||
~compile_time_sized_ringbuffer( void )
|
||||
{
|
||||
// destroy all remaining items
|
||||
detail::consume_noop consume_functor;
|
||||
(void)consume_all( consume_functor );
|
||||
consume_all( []( const T& ) {} );
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -458,25 +385,13 @@ public:
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor& f )
|
||||
bool consume_one( Functor&& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_one( f, data(), max_size );
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor const& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_one( f, data(), max_size );
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
size_type consume_all( Functor& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_all( f, data(), max_size );
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
size_type consume_all( Functor const& f )
|
||||
size_type consume_all( Functor&& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_all( f, data(), max_size );
|
||||
}
|
||||
@@ -523,15 +438,11 @@ public:
|
||||
template < typename T, typename Alloc >
|
||||
class runtime_sized_ringbuffer : public ringbuffer_base< T >, private Alloc
|
||||
{
|
||||
typedef std::size_t size_type;
|
||||
size_type max_elements_;
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
typedef typename Alloc::pointer pointer;
|
||||
#else
|
||||
typedef std::size_t size_type;
|
||||
size_type max_elements_;
|
||||
typedef std::allocator_traits< Alloc > allocator_traits;
|
||||
typedef typename allocator_traits::pointer pointer;
|
||||
#endif
|
||||
pointer array_;
|
||||
pointer array_;
|
||||
|
||||
protected:
|
||||
size_type max_number_of_elements() const
|
||||
@@ -543,12 +454,8 @@ public:
|
||||
explicit runtime_sized_ringbuffer( size_type max_elements ) :
|
||||
max_elements_( max_elements + 1 )
|
||||
{
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
array_ = Alloc::allocate( max_elements_ );
|
||||
#else
|
||||
Alloc& alloc = *this;
|
||||
array_ = allocator_traits::allocate( alloc, max_elements_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
template < typename U >
|
||||
@@ -556,38 +463,25 @@ public:
|
||||
Alloc( alloc ),
|
||||
max_elements_( max_elements + 1 )
|
||||
{
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
array_ = Alloc::allocate( max_elements_ );
|
||||
#else
|
||||
Alloc& allocator = *this;
|
||||
array_ = allocator_traits::allocate( allocator, max_elements_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
runtime_sized_ringbuffer( Alloc const& alloc, size_type max_elements ) :
|
||||
Alloc( alloc ),
|
||||
max_elements_( max_elements + 1 )
|
||||
{
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
array_ = Alloc::allocate( max_elements_ );
|
||||
#else
|
||||
Alloc& allocator = *this;
|
||||
array_ = allocator_traits::allocate( allocator, max_elements_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
~runtime_sized_ringbuffer( void )
|
||||
{
|
||||
// destroy all remaining items
|
||||
detail::consume_noop consume_functor;
|
||||
(void)consume_all( consume_functor );
|
||||
consume_all( []( const T& ) {} );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_ALLOCATOR
|
||||
Alloc::deallocate( array_, max_elements_ );
|
||||
#else
|
||||
Alloc& allocator = *this;
|
||||
allocator_traits::deallocate( allocator, array_, max_elements_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
bool push( T const& t )
|
||||
@@ -596,25 +490,13 @@ public:
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor& f )
|
||||
bool consume_one( Functor&& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_one( f, &*array_, max_elements_ );
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor const& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_one( f, &*array_, max_elements_ );
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
size_type consume_all( Functor& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_all( f, &*array_, max_elements_ );
|
||||
}
|
||||
|
||||
template < typename Functor >
|
||||
size_type consume_all( Functor const& f )
|
||||
size_type consume_all( Functor&& f )
|
||||
{
|
||||
return ringbuffer_base< T >::consume_all( f, &*array_, max_elements_ );
|
||||
}
|
||||
@@ -658,35 +540,30 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, typename A0, typename A1 >
|
||||
#else
|
||||
typedef parameter::parameters< boost::parameter::optional< tag::capacity >, boost::parameter::optional< tag::allocator > >
|
||||
ringbuffer_signature;
|
||||
|
||||
template < typename T, typename... Options >
|
||||
#endif
|
||||
struct make_ringbuffer
|
||||
{
|
||||
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
typedef typename ringbuffer_signature::bind< A0, A1 >::type bound_args;
|
||||
#else
|
||||
typedef typename ringbuffer_signature::bind< Options... >::type bound_args;
|
||||
#endif
|
||||
|
||||
typedef extract_capacity< bound_args > extract_capacity_t;
|
||||
|
||||
static const bool runtime_sized = !extract_capacity_t::has_capacity;
|
||||
static const size_t capacity = extract_capacity_t::capacity;
|
||||
static constexpr bool runtime_sized = !extract_capacity_t::has_capacity;
|
||||
static constexpr size_t capacity = extract_capacity_t::capacity;
|
||||
|
||||
typedef extract_allocator< bound_args, T > extract_allocator_t;
|
||||
static constexpr bool has_allocator = extract_allocator_t::has_allocator;
|
||||
typedef typename extract_allocator_t::type allocator;
|
||||
|
||||
// allocator argument is only sane, for run-time sized ringbuffers
|
||||
BOOST_STATIC_ASSERT( ( mpl::if_< mpl::bool_< !runtime_sized >,
|
||||
mpl::bool_< !extract_allocator_t::has_allocator >,
|
||||
mpl::true_ >::type::value ) );
|
||||
static constexpr bool signature_is_valid = runtime_sized ? true : !has_allocator;
|
||||
BOOST_STATIC_ASSERT( signature_is_valid );
|
||||
|
||||
typedef typename mpl::if_c< runtime_sized,
|
||||
typedef std::conditional_t< runtime_sized,
|
||||
runtime_sized_ringbuffer< T, allocator >,
|
||||
compile_time_sized_ringbuffer< T, capacity > >::type ringbuffer_type;
|
||||
compile_time_sized_ringbuffer< T, capacity > >
|
||||
ringbuffer_type;
|
||||
};
|
||||
|
||||
|
||||
@@ -707,31 +584,14 @@ struct make_ringbuffer
|
||||
* - T must have a default constructor
|
||||
* - T must be copyable
|
||||
* */
|
||||
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, class A0, class A1 >
|
||||
#else
|
||||
template < typename T, typename... Options >
|
||||
#endif
|
||||
class spsc_queue :
|
||||
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
public detail::make_ringbuffer< T, A0, A1 >::ringbuffer_type
|
||||
#else
|
||||
public detail::make_ringbuffer< T, Options... >::ringbuffer_type
|
||||
#endif
|
||||
class spsc_queue : public detail::make_ringbuffer< T, Options... >::ringbuffer_type
|
||||
{
|
||||
private:
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
|
||||
# ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
typedef typename detail::make_ringbuffer< T, A0, A1 >::ringbuffer_type base_type;
|
||||
static const bool runtime_sized = detail::make_ringbuffer< T, A0, A1 >::runtime_sized;
|
||||
typedef typename detail::make_ringbuffer< T, A0, A1 >::allocator allocator_arg;
|
||||
# else
|
||||
typedef typename detail::make_ringbuffer< T, Options... >::ringbuffer_type base_type;
|
||||
static const bool runtime_sized = detail::make_ringbuffer< T, Options... >::runtime_sized;
|
||||
static constexpr bool runtime_sized = detail::make_ringbuffer< T, Options... >::runtime_sized;
|
||||
typedef typename detail::make_ringbuffer< T, Options... >::allocator allocator_arg;
|
||||
# endif
|
||||
|
||||
|
||||
struct implementation_defined
|
||||
{
|
||||
@@ -762,11 +622,9 @@ public:
|
||||
*
|
||||
* \note This is just for API compatibility: an allocator isn't actually needed
|
||||
*/
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< !runtime_sized > >
|
||||
explicit spsc_queue( typename boost::allocator_rebind< allocator, U >::type const& )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( !runtime_sized );
|
||||
}
|
||||
{}
|
||||
|
||||
/** Constructs a spsc_queue with a custom allocator
|
||||
*
|
||||
@@ -774,47 +632,41 @@ public:
|
||||
*
|
||||
* \note This is just for API compatibility: an allocator isn't actually needed
|
||||
*/
|
||||
template < typename Enabler = std::enable_if< !runtime_sized > >
|
||||
explicit spsc_queue( allocator const& )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( !runtime_sized );
|
||||
}
|
||||
{}
|
||||
|
||||
/** Constructs a spsc_queue for element_count elements
|
||||
*
|
||||
* \pre spsc_queue must be configured to be sized at run-time
|
||||
*/
|
||||
template < typename Enabler = std::enable_if< runtime_sized > >
|
||||
explicit spsc_queue( size_type element_count ) :
|
||||
base_type( element_count )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( runtime_sized );
|
||||
}
|
||||
{}
|
||||
|
||||
/** Constructs a spsc_queue for element_count elements with a custom allocator
|
||||
*
|
||||
* \pre spsc_queue must be configured to be sized at run-time
|
||||
*/
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< runtime_sized > >
|
||||
spsc_queue( size_type element_count, typename boost::allocator_rebind< allocator, U >::type const& alloc ) :
|
||||
base_type( alloc, element_count )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( runtime_sized );
|
||||
}
|
||||
{}
|
||||
|
||||
/** Constructs a spsc_queue for element_count elements with a custom allocator
|
||||
*
|
||||
* \pre spsc_queue must be configured to be sized at run-time
|
||||
*/
|
||||
template < typename Enabler = std::enable_if< runtime_sized > >
|
||||
spsc_queue( size_type element_count, allocator_arg const& alloc ) :
|
||||
base_type( alloc, element_count )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( runtime_sized );
|
||||
}
|
||||
{}
|
||||
|
||||
spsc_queue( const spsc_queue& ) = delete;
|
||||
spsc_queue& operator=( const spsc_queue& ) = delete;
|
||||
spsc_queue( spsc_queue&& ) = delete;
|
||||
spsc_queue& operator=( spsc_queue&& ) = delete;
|
||||
|
||||
/** Pushes object t to the ringbuffer.
|
||||
*
|
||||
@@ -839,8 +691,7 @@ public:
|
||||
*/
|
||||
bool pop()
|
||||
{
|
||||
detail::consume_noop consume_functor;
|
||||
return consume_one( consume_functor );
|
||||
return consume_one( []( const T& ) {} );
|
||||
}
|
||||
|
||||
/** Pops one object from ringbuffer.
|
||||
@@ -851,11 +702,12 @@ public:
|
||||
*
|
||||
* \note Thread-safe and wait-free
|
||||
*/
|
||||
template < typename U >
|
||||
typename boost::enable_if< typename is_convertible< T, U >::type, bool >::type pop( U& ret )
|
||||
template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > >
|
||||
bool pop( U& ret )
|
||||
{
|
||||
detail::consume_via_copy< U > consume_functor( ret );
|
||||
return consume_one( consume_functor );
|
||||
return consume_one( [ & ]( const T& t ) {
|
||||
ret = std::move( t );
|
||||
} );
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the array t as there is space.
|
||||
@@ -883,6 +735,19 @@ public:
|
||||
return push( t, size );
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the span t as there is space available.
|
||||
*
|
||||
* \pre only one thread is allowed to push data to the spsc_queue
|
||||
* \return number of pushed items
|
||||
*
|
||||
* \note Thread-safe and wait-free
|
||||
*/
|
||||
template < std::size_t Extent >
|
||||
size_type push( boost::span< const T, Extent > t )
|
||||
{
|
||||
return push( t.data(), t.size() );
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the range [begin, end) as there is space .
|
||||
*
|
||||
* \pre only one thread is allowed to push data to the spsc_queue
|
||||
@@ -929,8 +794,7 @@ public:
|
||||
* \note Thread-safe and wait-free
|
||||
* */
|
||||
template < typename OutputIterator >
|
||||
typename boost::disable_if< typename is_convertible< T, OutputIterator >::type, size_type >::type
|
||||
pop( OutputIterator it )
|
||||
typename std::enable_if< !std::is_convertible< T, OutputIterator >::value, size_type >::type pop( OutputIterator it )
|
||||
{
|
||||
return base_type::pop_to_output_iterator( it );
|
||||
}
|
||||
@@ -944,14 +808,7 @@ public:
|
||||
* \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking
|
||||
* */
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor& f )
|
||||
{
|
||||
return base_type::consume_one( f );
|
||||
}
|
||||
|
||||
/// \copydoc boost::lockfree::spsc_queue::consume_one(Functor & rhs)
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor const& f )
|
||||
bool consume_one( Functor&& f )
|
||||
{
|
||||
return base_type::consume_one( f );
|
||||
}
|
||||
@@ -965,14 +822,7 @@ public:
|
||||
* \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking
|
||||
* */
|
||||
template < typename Functor >
|
||||
size_type consume_all( Functor& f )
|
||||
{
|
||||
return base_type::consume_all( f );
|
||||
}
|
||||
|
||||
/// \copydoc boost::lockfree::spsc_queue::consume_all(Functor & rhs)
|
||||
template < typename Functor >
|
||||
size_type consume_all( Functor const& f )
|
||||
size_type consume_all( Functor&& f )
|
||||
{
|
||||
return base_type::consume_all( f );
|
||||
}
|
||||
@@ -1028,11 +878,9 @@ public:
|
||||
* */
|
||||
void reset( void )
|
||||
{
|
||||
if ( !boost::has_trivial_destructor< T >::value ) {
|
||||
if ( !std::is_trivially_destructible< T >::value ) {
|
||||
// make sure to call all destructors!
|
||||
|
||||
detail::consume_noop consume_functor;
|
||||
(void)consume_all( consume_functor );
|
||||
consume_all( []( const T& ) {} );
|
||||
} else {
|
||||
base_type::write_index_.store( 0, memory_order_relaxed );
|
||||
base_type::read_index_.store( 0, memory_order_release );
|
||||
|
||||
+115
-219
@@ -8,22 +8,23 @@
|
||||
#define BOOST_LOCKFREE_STACK_HPP_INCLUDED
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/checked_delete.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/integer_traits.hpp>
|
||||
#include <boost/core/span.hpp>
|
||||
#include <boost/parameter/optional.hpp>
|
||||
#include <boost/parameter/parameters.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/type_traits/is_copy_constructible.hpp>
|
||||
|
||||
#include <boost/lockfree/detail/atomic.hpp>
|
||||
#include <boost/lockfree/detail/copy_payload.hpp>
|
||||
#include <boost/lockfree/detail/freelist.hpp>
|
||||
#include <boost/lockfree/detail/parameter.hpp>
|
||||
#include <boost/lockfree/detail/tagged_ptr.hpp>
|
||||
|
||||
#include <boost/lockfree/lockfree_forward.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
# pragma once
|
||||
#endif
|
||||
@@ -59,22 +60,14 @@ typedef parameter::parameters< boost::parameter::optional< tag::allocator >, boo
|
||||
* \b Requirements:
|
||||
* - T must have a copy constructor
|
||||
* */
|
||||
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template < typename T, class A0, class A1, class A2 >
|
||||
#else
|
||||
template < typename T, typename... Options >
|
||||
#endif
|
||||
class stack
|
||||
{
|
||||
private:
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
BOOST_STATIC_ASSERT( boost::is_copy_constructible< T >::value );
|
||||
BOOST_STATIC_ASSERT( std::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;
|
||||
@@ -99,21 +92,17 @@ private:
|
||||
typedef typename pool_t::tagged_node_handle tagged_node_handle;
|
||||
|
||||
// check compile-time capacity
|
||||
BOOST_STATIC_ASSERT( ( mpl::if_c< has_capacity,
|
||||
mpl::bool_< capacity - 1 < boost::integer_traits< boost::uint16_t >::const_max >,
|
||||
mpl::true_ >::type::value ) );
|
||||
static constexpr bool capacity_is_valid = has_capacity ? capacity - 1 < std::numeric_limits< std::uint16_t >::max()
|
||||
: true;
|
||||
BOOST_STATIC_ASSERT( capacity_is_valid );
|
||||
|
||||
struct implementation_defined
|
||||
{
|
||||
typedef node_allocator allocator;
|
||||
typedef std::size_t size_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_DELETED_FUNCTION( stack( stack const& ) )
|
||||
BOOST_DELETED_FUNCTION( stack& operator=( stack const& ) )
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef typename implementation_defined::allocator allocator;
|
||||
@@ -137,7 +126,7 @@ public:
|
||||
*
|
||||
* \pre Must specify a capacity<> argument
|
||||
* */
|
||||
stack( void ) :
|
||||
explicit stack( void ) :
|
||||
pool( node_allocator(), capacity )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
@@ -150,11 +139,10 @@ public:
|
||||
*
|
||||
* \pre Must specify a capacity<> argument
|
||||
* */
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< has_capacity > >
|
||||
explicit stack( typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) :
|
||||
pool( alloc, capacity )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -162,12 +150,10 @@ public:
|
||||
*
|
||||
* \pre Must specify a capacity<> argument
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< has_capacity > >
|
||||
explicit stack( allocator const& alloc ) :
|
||||
pool( alloc, capacity )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -177,26 +163,29 @@ public:
|
||||
*
|
||||
* \pre Must \b not specify a capacity<> argument
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< !has_capacity > >
|
||||
explicit stack( size_type n ) :
|
||||
pool( node_allocator(), n )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( !has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
stack( const stack& ) = delete;
|
||||
stack& operator=( const stack& ) = delete;
|
||||
stack( stack&& ) = delete;
|
||||
stack& operator=( stack&& ) = delete;
|
||||
|
||||
|
||||
/** Construct a variable-sized stack with a custom allocator
|
||||
*
|
||||
* Allocate n nodes initially for the freelist
|
||||
*
|
||||
* \pre Must \b not specify a capacity<> argument
|
||||
* */
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< !has_capacity > >
|
||||
stack( size_type n, typename boost::allocator_rebind< node_allocator, U >::type const& alloc ) :
|
||||
pool( alloc, n )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( !has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -206,10 +195,10 @@ public:
|
||||
*
|
||||
* \pre Must \b not specify a capacity<> argument
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< !has_capacity > >
|
||||
stack( size_type n, node_allocator const& alloc ) :
|
||||
pool( alloc, n )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( !has_capacity );
|
||||
initialize();
|
||||
}
|
||||
|
||||
@@ -219,11 +208,9 @@ public:
|
||||
* \note thread-safe, may block if memory allocator blocks
|
||||
*
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< !has_capacity > >
|
||||
void reserve( size_type n )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( !has_capacity );
|
||||
pool.template reserve< true >( n );
|
||||
}
|
||||
|
||||
@@ -233,11 +220,9 @@ public:
|
||||
* \note not thread-safe, may block if memory allocator blocks
|
||||
*
|
||||
* */
|
||||
template < typename Enabler = std::enable_if< !has_capacity > >
|
||||
void reserve_unsafe( size_type n )
|
||||
{
|
||||
// Don't use BOOST_STATIC_ASSERT() here since it will be evaluated when compiling
|
||||
// this function and this function may be compiled even when it isn't being used.
|
||||
BOOST_ASSERT( !has_capacity );
|
||||
pool.template reserve< false >( n );
|
||||
}
|
||||
|
||||
@@ -248,8 +233,7 @@ public:
|
||||
* */
|
||||
~stack( void )
|
||||
{
|
||||
detail::consume_noop consume_functor;
|
||||
(void)consume_all( consume_functor );
|
||||
consume_all( []( const T& ) {} );
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -282,13 +266,13 @@ private:
|
||||
}
|
||||
|
||||
template < bool Threadsafe, bool Bounded, typename ConstIterator >
|
||||
tuple< node*, node* > prepare_node_list( ConstIterator begin, ConstIterator end, ConstIterator& ret )
|
||||
std::tuple< node*, node* > prepare_node_list( ConstIterator begin, ConstIterator end, ConstIterator& ret )
|
||||
{
|
||||
ConstIterator it = begin;
|
||||
node* end_node = pool.template construct< Threadsafe, Bounded >( *it++ );
|
||||
if ( end_node == NULL ) {
|
||||
ret = begin;
|
||||
return make_tuple< node*, node* >( NULL, NULL );
|
||||
return std::make_tuple< node*, node* >( NULL, NULL );
|
||||
}
|
||||
|
||||
node* new_top_node = end_node;
|
||||
@@ -317,7 +301,32 @@ private:
|
||||
BOOST_CATCH_END
|
||||
|
||||
ret = it;
|
||||
return make_tuple( new_top_node, end_node );
|
||||
return std::make_tuple( new_top_node, end_node );
|
||||
}
|
||||
|
||||
template < bool Bounded >
|
||||
bool do_push( T const& v )
|
||||
{
|
||||
node* newnode = pool.template construct< true, Bounded >( v );
|
||||
if ( newnode == 0 )
|
||||
return false;
|
||||
|
||||
link_nodes_atomic( newnode, newnode );
|
||||
return true;
|
||||
}
|
||||
|
||||
template < bool Bounded, typename ConstIterator >
|
||||
ConstIterator do_push( ConstIterator begin, ConstIterator end )
|
||||
{
|
||||
node* new_top_node;
|
||||
node* end_node;
|
||||
ConstIterator ret;
|
||||
|
||||
std::tie( new_top_node, end_node ) = prepare_node_list< true, Bounded >( begin, end, ret );
|
||||
if ( new_top_node )
|
||||
link_nodes_atomic( new_top_node, end_node );
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -347,43 +356,15 @@ public:
|
||||
return do_push< true >( v );
|
||||
}
|
||||
|
||||
#ifndef BOOST_DOXYGEN_INVOKED
|
||||
private:
|
||||
template < bool Bounded >
|
||||
bool do_push( T const& v )
|
||||
{
|
||||
node* newnode = pool.template construct< true, Bounded >( v );
|
||||
if ( newnode == 0 )
|
||||
return false;
|
||||
|
||||
link_nodes_atomic( newnode, newnode );
|
||||
return true;
|
||||
}
|
||||
|
||||
template < bool Bounded, typename ConstIterator >
|
||||
ConstIterator do_push( ConstIterator begin, ConstIterator end )
|
||||
{
|
||||
node* new_top_node;
|
||||
node* end_node;
|
||||
ConstIterator ret;
|
||||
|
||||
tie( new_top_node, end_node ) = prepare_node_list< true, Bounded >( begin, end, ret );
|
||||
if ( new_top_node )
|
||||
link_nodes_atomic( new_top_node, end_node );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
/** Pushes as many objects from the range [begin, end) as freelist node can be allocated.
|
||||
*
|
||||
* \return iterator to the first element, which has not been pushed
|
||||
*
|
||||
* \note Operation is applied atomically
|
||||
* \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will
|
||||
* be allocated from the OS. This may not be lock-free. \throws if memory allocator throws
|
||||
* be allocated from the OS. This may not be lock-free.
|
||||
*
|
||||
* \throws if memory allocator throws
|
||||
*/
|
||||
template < typename ConstIterator >
|
||||
ConstIterator push( ConstIterator begin, ConstIterator end )
|
||||
@@ -391,6 +372,23 @@ public:
|
||||
return do_push< false, ConstIterator >( begin, end );
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the span as freelist node can be allocated.
|
||||
*
|
||||
* \return Number of elements pushed
|
||||
*
|
||||
* \note Operation is applied atomically
|
||||
* \note Thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node will
|
||||
* be allocated from the OS. This may not be lock-free.
|
||||
*
|
||||
* \throws if memory allocator throws
|
||||
*/
|
||||
template < std::size_t Extent >
|
||||
size_type push( boost::span< const T, Extent > t )
|
||||
{
|
||||
const T* end_pushed = push( t.begin(), t.end() );
|
||||
return std::distance( t.begin(), end_pushed );
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the range [begin, end) as freelist node can be allocated.
|
||||
*
|
||||
* \return iterator to the first element, which has not been pushed
|
||||
@@ -405,6 +403,21 @@ public:
|
||||
return do_push< true, ConstIterator >( begin, end );
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the span as freelist node can be allocated.
|
||||
*
|
||||
* \return Number of elements pushed
|
||||
*
|
||||
* \note Operation is applied atomically
|
||||
* \note Thread-safe and non-blocking. If internal memory pool is exhausted, the push operation will fail
|
||||
* \throws if memory allocator throws
|
||||
*/
|
||||
template < std::size_t Extent >
|
||||
size_type bounded_push( boost::span< const T, Extent > t )
|
||||
{
|
||||
const T* end_pushed = bounded_push( t.begin(), t.end() );
|
||||
return std::distance( t.begin(), end_pushed );
|
||||
}
|
||||
|
||||
|
||||
/** Pushes object t to the stack.
|
||||
*
|
||||
@@ -412,7 +425,8 @@ public:
|
||||
* \returns true, if the push operation is successful.
|
||||
*
|
||||
* \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node
|
||||
* will be allocated from the OS. This may not be lock-free. \throws if memory allocator throws
|
||||
* will be allocated from the OS. This may not be lock-free.
|
||||
* \throws if memory allocator throws
|
||||
* */
|
||||
bool unsynchronized_push( T const& v )
|
||||
{
|
||||
@@ -429,7 +443,8 @@ public:
|
||||
* \return iterator to the first element, which has not been pushed
|
||||
*
|
||||
* \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node
|
||||
* will be allocated from the OS. This may not be lock-free. \throws if memory allocator throws
|
||||
* will be allocated from the OS. This may not be lock-free.
|
||||
* \throws if memory allocator throws
|
||||
*/
|
||||
template < typename ConstIterator >
|
||||
ConstIterator unsynchronized_push( ConstIterator begin, ConstIterator end )
|
||||
@@ -438,13 +453,26 @@ public:
|
||||
node* end_node;
|
||||
ConstIterator ret;
|
||||
|
||||
tie( new_top_node, end_node ) = prepare_node_list< false, false >( begin, end, ret );
|
||||
std::tie( new_top_node, end_node ) = prepare_node_list< false, false >( begin, end, ret );
|
||||
if ( new_top_node )
|
||||
link_nodes_unsafe( new_top_node, end_node );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Pushes as many objects from the span as freelist node can be allocated.
|
||||
*
|
||||
* \return iterator to the first element, which has not been pushed
|
||||
*
|
||||
* \note Not thread-safe. If internal memory pool is exhausted and the memory pool is not fixed-sized, a new node
|
||||
* will be allocated from the OS. This may not be lock-free. \throws if memory allocator throws
|
||||
*/
|
||||
template < std::size_t Extent >
|
||||
size_type unsynchronized_push( boost::span< const T, Extent > t )
|
||||
{
|
||||
const T* end_pushed = unsynchronized_push( t.begin(), t.end() );
|
||||
return std::distance( t.begin(), end_pushed );
|
||||
}
|
||||
|
||||
/** Pops object from stack.
|
||||
*
|
||||
@@ -468,13 +496,12 @@ public:
|
||||
* \note Thread-safe and non-blocking
|
||||
*
|
||||
* */
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > >
|
||||
bool pop( U& ret )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( ( boost::is_convertible< T, U >::value ) );
|
||||
detail::consume_via_copy< U > consumer( ret );
|
||||
|
||||
return consume_one( consumer );
|
||||
return consume_one( [ & ]( const T& t ) {
|
||||
ret = U( t );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@@ -500,10 +527,9 @@ public:
|
||||
* \note Not thread-safe, but non-blocking
|
||||
*
|
||||
* */
|
||||
template < typename U >
|
||||
template < typename U, typename Enabler = std::enable_if< std::is_convertible< T, U >::value > >
|
||||
bool unsynchronized_pop( U& ret )
|
||||
{
|
||||
BOOST_STATIC_ASSERT( ( boost::is_convertible< T, U >::value ) );
|
||||
tagged_node_handle old_tos = tos.load( detail::memory_order_relaxed );
|
||||
node* old_tos_pointer = pool.get_pointer( old_tos );
|
||||
|
||||
@@ -528,28 +554,7 @@ public:
|
||||
* \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking
|
||||
* */
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor& f )
|
||||
{
|
||||
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 false;
|
||||
|
||||
tagged_node_handle new_tos( old_tos_pointer->next, old_tos.get_next_tag() );
|
||||
|
||||
if ( tos.compare_exchange_weak( old_tos, new_tos ) ) {
|
||||
f( old_tos_pointer->v );
|
||||
pool.template destruct< true >( old_tos );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \copydoc boost::lockfree::stack::consume_one(Functor & rhs)
|
||||
template < typename Functor >
|
||||
bool consume_one( Functor const& f )
|
||||
bool consume_one( Functor&& f )
|
||||
{
|
||||
tagged_node_handle old_tos = tos.load( detail::memory_order_consume );
|
||||
|
||||
@@ -577,18 +582,7 @@ public:
|
||||
* \note Thread-safe and non-blocking, if functor is thread-safe and non-blocking
|
||||
* */
|
||||
template < typename Functor >
|
||||
size_t consume_all( Functor& f )
|
||||
{
|
||||
size_t element_count = 0;
|
||||
while ( consume_one( f ) )
|
||||
element_count += 1;
|
||||
|
||||
return element_count;
|
||||
}
|
||||
|
||||
/// \copydoc boost::lockfree::stack::consume_all(Functor & rhs)
|
||||
template < typename Functor >
|
||||
size_t consume_all( Functor const& f )
|
||||
size_t consume_all( Functor&& f )
|
||||
{
|
||||
size_t element_count = 0;
|
||||
while ( consume_one( f ) )
|
||||
@@ -606,47 +600,7 @@ public:
|
||||
* \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( 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;
|
||||
|
||||
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 consume_all_atomic( Functor&& f )
|
||||
{
|
||||
size_t element_count = 0;
|
||||
tagged_node_handle old_tos = tos.load( detail::memory_order_consume );
|
||||
@@ -693,65 +647,7 @@ public:
|
||||
* \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 consume_all_atomic_reversed( Functor&& f )
|
||||
{
|
||||
size_t element_count = 0;
|
||||
tagged_node_handle old_tos = tos.load( detail::memory_order_consume );
|
||||
|
||||
+1
-1
@@ -11,5 +11,5 @@
|
||||
"maintainers": [
|
||||
"Tim Blechmann <tim -at- klingt.org>"
|
||||
],
|
||||
"cxxstd": "03"
|
||||
"cxxstd": "14"
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,6 @@ foreach(Test ${Tests})
|
||||
set (Libs Boost::lockfree
|
||||
Boost::unit_test_framework
|
||||
Boost::thread
|
||||
Boost::foreach
|
||||
boost_lockfree_test_common)
|
||||
|
||||
if (Test MATCHES ".*interprocess.*")
|
||||
@@ -58,6 +57,7 @@ foreach(Test ${Tests})
|
||||
LINK_LIBRARIES ${Libs}
|
||||
COMPILE_DEFINITIONS BOOST_TEST_NO_OLD_TOOLS
|
||||
)
|
||||
set_target_properties( boost_lockfree-${Test} PROPERTIES CMAKE_CXX_STANDARD_REQUIRED 14)
|
||||
|
||||
if (TARGET boost_lockfree-${Test})
|
||||
add_dependencies(boost_lockfree_all_tests boost_lockfree-${Test} )
|
||||
|
||||
+11
-9
@@ -10,9 +10,7 @@
|
||||
#include <boost/lockfree/detail/freelist.hpp>
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
@@ -66,14 +64,14 @@ void run_test( void )
|
||||
nodes.insert( allocated );
|
||||
}
|
||||
|
||||
BOOST_FOREACH ( dummy* d, nodes )
|
||||
for ( dummy* d : nodes )
|
||||
fl.template destruct< threadsafe >( d );
|
||||
|
||||
nodes.clear();
|
||||
for ( int i = 0; i != 4; ++i )
|
||||
nodes.insert( fl.template construct< threadsafe, bounded >() );
|
||||
|
||||
BOOST_FOREACH ( dummy* d, nodes )
|
||||
for ( dummy* d : nodes )
|
||||
fl.template destruct< threadsafe >( d );
|
||||
|
||||
for ( int i = 0; i != 4; ++i )
|
||||
@@ -152,10 +150,14 @@ struct freelist_tester
|
||||
boost::thread_group dealloc_threads;
|
||||
|
||||
for ( int i = 0; i != thread_count; ++i )
|
||||
dealloc_threads.create_thread( boost::bind( &freelist_tester::deallocate, this ) );
|
||||
dealloc_threads.create_thread( [ this ] {
|
||||
deallocate();
|
||||
} );
|
||||
|
||||
for ( int i = 0; i != thread_count; ++i )
|
||||
alloc_threads.create_thread( boost::bind( &freelist_tester::allocate, this ) );
|
||||
alloc_threads.create_thread( [ this ] {
|
||||
allocate();
|
||||
} );
|
||||
alloc_threads.join_all();
|
||||
test_running.store( false );
|
||||
running = false;
|
||||
@@ -193,7 +195,7 @@ struct freelist_tester
|
||||
break;
|
||||
|
||||
#ifdef __VXWORKS__
|
||||
boost::thread::yield();
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -210,7 +212,7 @@ struct freelist_tester
|
||||
template < typename Tester >
|
||||
void run_tester()
|
||||
{
|
||||
boost::scoped_ptr< Tester > tester( new Tester );
|
||||
std::unique_ptr< Tester > tester( new Tester );
|
||||
tester->run();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
# include <boost/test/included/unit_test.hpp>
|
||||
@@ -20,7 +18,7 @@
|
||||
BOOST_AUTO_TEST_CASE( queue_test_bounded )
|
||||
{
|
||||
typedef queue_stress_tester< true > tester_type;
|
||||
boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
|
||||
boost::lockfree::queue< long > q( 128 );
|
||||
tester->run( q );
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
# include <boost/test/included/unit_test.hpp>
|
||||
@@ -20,8 +18,8 @@
|
||||
|
||||
BOOST_AUTO_TEST_CASE( queue_test_fixed_size )
|
||||
{
|
||||
typedef queue_stress_tester<> tester_type;
|
||||
boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
typedef queue_stress_tester<> tester_type;
|
||||
std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
|
||||
boost::lockfree::queue< long, boost::lockfree::capacity< 8 > > q;
|
||||
tester->run( q );
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cstdlib> //std::system
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
using namespace boost::interprocess;
|
||||
typedef allocator< int, managed_shared_memory::segment_manager > ShmemAllocator;
|
||||
@@ -42,7 +42,7 @@ int main( int argc, char* argv[] )
|
||||
return 1;
|
||||
|
||||
while ( !q->empty() )
|
||||
boost::thread::yield();
|
||||
std::this_thread::yield();
|
||||
return 0;
|
||||
} else {
|
||||
managed_shared_memory segment( open_only, "boost_queue_interprocess_test_shm" );
|
||||
|
||||
+2
-15
@@ -95,18 +95,13 @@ BOOST_AUTO_TEST_CASE( queue_consume_one_test )
|
||||
f.push( 1 );
|
||||
f.push( 2 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
bool success1 = f.consume_one( test_equal( 1 ) );
|
||||
bool success2 = f.consume_one( test_equal( 2 ) );
|
||||
#else
|
||||
bool success1 = f.consume_one( []( int i ) {
|
||||
BOOST_TEST_REQUIRE( i == 1 );
|
||||
} );
|
||||
|
||||
bool success2 = f.consume_one( []( int i ) {
|
||||
bool success2 = f.consume_one( []( int i ) mutable {
|
||||
BOOST_TEST_REQUIRE( i == 2 );
|
||||
} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( success1 );
|
||||
BOOST_TEST_REQUIRE( success2 );
|
||||
@@ -124,11 +119,7 @@ BOOST_AUTO_TEST_CASE( queue_consume_all_test )
|
||||
f.push( 1 );
|
||||
f.push( 2 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
size_t consumed = f.consume_all( dummy_functor() );
|
||||
#else
|
||||
size_t consumed = f.consume_all( []( int i ) {} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( consumed == 2u );
|
||||
|
||||
@@ -161,18 +152,14 @@ BOOST_AUTO_TEST_CASE( queue_convert_pop_test )
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef BOOST_NO_AUTO_PTR
|
||||
unique_ptr< int > i3;
|
||||
#else
|
||||
auto_ptr< int > i3;
|
||||
#endif
|
||||
BOOST_TEST_REQUIRE( f.pop( i3 ) );
|
||||
|
||||
BOOST_TEST_REQUIRE( *i3 == 3 );
|
||||
}
|
||||
|
||||
{
|
||||
boost::shared_ptr< int > i4;
|
||||
std::shared_ptr< int > i4;
|
||||
BOOST_TEST_REQUIRE( f.pop( i4 ) );
|
||||
|
||||
BOOST_TEST_REQUIRE( *i4 == 4 );
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
# include <boost/test/included/unit_test.hpp>
|
||||
@@ -20,7 +18,7 @@
|
||||
BOOST_AUTO_TEST_CASE( queue_test_unbounded )
|
||||
{
|
||||
typedef queue_stress_tester< false > tester_type;
|
||||
boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
|
||||
boost::lockfree::queue< long > q( 128 );
|
||||
tester->run( q );
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/lockfree/spsc_queue.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
@@ -14,8 +13,10 @@
|
||||
# include <boost/test/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "test_common.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
@@ -34,7 +35,7 @@ struct spsc_queue_tester
|
||||
{
|
||||
spsc_queue< int, capacity< 128 > > sf;
|
||||
|
||||
boost::lockfree::detail::atomic< long > spsc_queue_cnt, received_nodes;
|
||||
std::atomic< long > spsc_queue_cnt, received_nodes;
|
||||
|
||||
// In VxWorks one RTP just supports 65535 objects
|
||||
#ifndef __VXWORKS__
|
||||
@@ -77,7 +78,7 @@ struct spsc_queue_tester
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::lockfree::detail::atomic< bool > running;
|
||||
std::atomic< bool > running;
|
||||
|
||||
void get( void )
|
||||
{
|
||||
@@ -97,8 +98,13 @@ struct spsc_queue_tester
|
||||
|
||||
BOOST_TEST_REQUIRE( sf.empty() );
|
||||
|
||||
boost::thread reader( boost::bind( &spsc_queue_tester::get, this ) );
|
||||
boost::thread writer( boost::bind( &spsc_queue_tester::add, this ) );
|
||||
std::thread reader( [ & ] {
|
||||
get();
|
||||
} );
|
||||
|
||||
std::thread writer( [ & ] {
|
||||
add();
|
||||
} );
|
||||
cout << "reader and writer threads created" << endl;
|
||||
|
||||
writer.join();
|
||||
@@ -115,7 +121,7 @@ struct spsc_queue_tester
|
||||
|
||||
BOOST_AUTO_TEST_CASE( spsc_queue_test_caching )
|
||||
{
|
||||
boost::shared_ptr< spsc_queue_tester > test1( new spsc_queue_tester );
|
||||
std::shared_ptr< spsc_queue_tester > test1( new spsc_queue_tester );
|
||||
test1->run();
|
||||
}
|
||||
|
||||
@@ -123,7 +129,7 @@ struct spsc_queue_tester_buffering
|
||||
{
|
||||
spsc_queue< int, capacity< 128 > > sf;
|
||||
|
||||
boost::lockfree::detail::atomic< long > spsc_queue_cnt;
|
||||
std::atomic< long > spsc_queue_cnt;
|
||||
|
||||
// In VxWorks one RTP just supports 65535 objects
|
||||
#ifndef __VXWORKS__
|
||||
@@ -132,7 +138,7 @@ struct spsc_queue_tester_buffering
|
||||
static_hashed_set< int, 1 << 15 > working_set;
|
||||
#endif
|
||||
|
||||
boost::lockfree::detail::atomic< size_t > received_nodes;
|
||||
std::atomic< size_t > received_nodes;
|
||||
|
||||
spsc_queue_tester_buffering( void ) :
|
||||
spsc_queue_cnt( 0 ),
|
||||
@@ -143,7 +149,7 @@ struct spsc_queue_tester_buffering
|
||||
|
||||
void add( void )
|
||||
{
|
||||
boost::array< int, buf_size > input_buffer;
|
||||
std::array< int, buf_size > input_buffer;
|
||||
for ( size_t i = 0; i != nodes_per_thread; i += buf_size ) {
|
||||
for ( size_t i = 0; i != buf_size; ++i ) {
|
||||
int id = generate_id< int >();
|
||||
@@ -154,7 +160,7 @@ struct spsc_queue_tester_buffering
|
||||
size_t pushed = 0;
|
||||
|
||||
do {
|
||||
pushed += sf.push( input_buffer.c_array() + pushed, input_buffer.size() - pushed );
|
||||
pushed += sf.push( input_buffer.data() + pushed, input_buffer.size() - pushed );
|
||||
} while ( pushed != buf_size );
|
||||
|
||||
spsc_queue_cnt += buf_size;
|
||||
@@ -164,9 +170,9 @@ struct spsc_queue_tester_buffering
|
||||
|
||||
bool get_elements( void )
|
||||
{
|
||||
boost::array< int, buf_size > output_buffer;
|
||||
std::array< int, buf_size > output_buffer;
|
||||
|
||||
size_t popd = sf.pop( output_buffer.c_array(), output_buffer.size() );
|
||||
size_t popd = sf.pop( output_buffer.data(), output_buffer.size() );
|
||||
|
||||
if ( popd ) {
|
||||
received_nodes += size_t( popd );
|
||||
@@ -183,7 +189,7 @@ struct spsc_queue_tester_buffering
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::lockfree::detail::atomic< bool > running;
|
||||
std::atomic< bool > running;
|
||||
|
||||
void get( void )
|
||||
{
|
||||
@@ -201,8 +207,14 @@ struct spsc_queue_tester_buffering
|
||||
{
|
||||
running = true;
|
||||
|
||||
boost::thread reader( boost::bind( &spsc_queue_tester_buffering::get, this ) );
|
||||
boost::thread writer( boost::bind( &spsc_queue_tester_buffering::add, this ) );
|
||||
std::thread reader( [ & ] {
|
||||
get();
|
||||
} );
|
||||
|
||||
std::thread writer( [ & ] {
|
||||
add();
|
||||
} );
|
||||
|
||||
cout << "reader and writer threads created" << endl;
|
||||
|
||||
writer.join();
|
||||
@@ -220,6 +232,6 @@ struct spsc_queue_tester_buffering
|
||||
|
||||
BOOST_AUTO_TEST_CASE( spsc_queue_test_buffering )
|
||||
{
|
||||
boost::shared_ptr< spsc_queue_tester_buffering > test1( new spsc_queue_tester_buffering );
|
||||
std::shared_ptr< spsc_queue_tester_buffering > test1( new spsc_queue_tester_buffering );
|
||||
test1->run();
|
||||
}
|
||||
|
||||
+11
-24
@@ -13,11 +13,7 @@
|
||||
# include <boost/test/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "test_common.hpp"
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::lockfree;
|
||||
@@ -85,10 +81,6 @@ BOOST_AUTO_TEST_CASE( spsc_queue_consume_one_test )
|
||||
f.push( 1 );
|
||||
f.push( 2 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
bool success1 = f.consume_one( test_equal( 1 ) );
|
||||
bool success2 = f.consume_one( test_equal( 2 ) );
|
||||
#else
|
||||
bool success1 = f.consume_one( []( int i ) {
|
||||
BOOST_TEST_REQUIRE( i == 1 );
|
||||
} );
|
||||
@@ -96,7 +88,6 @@ BOOST_AUTO_TEST_CASE( spsc_queue_consume_one_test )
|
||||
bool success2 = f.consume_one( []( int i ) {
|
||||
BOOST_TEST_REQUIRE( i == 2 );
|
||||
} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( success1 );
|
||||
BOOST_TEST_REQUIRE( success2 );
|
||||
@@ -114,11 +105,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_consume_all_test )
|
||||
f.push( 1 );
|
||||
f.push( 2 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
size_t consumed = f.consume_all( dummy_functor() );
|
||||
#else
|
||||
size_t consumed = f.consume_all( []( int i ) {} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( consumed == 2u );
|
||||
|
||||
@@ -130,6 +117,7 @@ enum
|
||||
pointer_and_size,
|
||||
reference_to_array,
|
||||
iterator_pair,
|
||||
span_,
|
||||
output_iterator_
|
||||
};
|
||||
|
||||
@@ -196,19 +184,18 @@ void spsc_queue_buffer_push_return_value( void )
|
||||
|
||||
switch ( EnqueueMode ) {
|
||||
case pointer_and_size: BOOST_TEST_REQUIRE( rb.push( data, xqueue_size ) == xqueue_size ); break;
|
||||
|
||||
case reference_to_array: BOOST_TEST_REQUIRE( rb.push( data ) == xqueue_size ); break;
|
||||
|
||||
case iterator_pair: BOOST_TEST_REQUIRE( rb.push( data, data + xqueue_size ) == data + xqueue_size ); break;
|
||||
|
||||
case span_: BOOST_TEST_REQUIRE( rb.push( boost::span< const int >( data, xqueue_size ) ) == xqueue_size ); break;
|
||||
default: assert( false );
|
||||
}
|
||||
|
||||
switch ( EnqueueMode ) {
|
||||
case pointer_and_size: BOOST_TEST_REQUIRE( rb.push( data, xqueue_size ) == buffer_size - xqueue_size ); break;
|
||||
|
||||
case reference_to_array: BOOST_TEST_REQUIRE( rb.push( data ) == buffer_size - xqueue_size ); break;
|
||||
|
||||
case span_:
|
||||
BOOST_TEST_REQUIRE( rb.push( boost::span< const int >( data, xqueue_size ) ) == buffer_size - xqueue_size );
|
||||
break;
|
||||
case iterator_pair:
|
||||
BOOST_TEST_REQUIRE( rb.push( data, data + xqueue_size ) == data + buffer_size - xqueue_size );
|
||||
break;
|
||||
@@ -222,6 +209,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_return_value_test )
|
||||
spsc_queue_buffer_push_return_value< pointer_and_size >();
|
||||
spsc_queue_buffer_push_return_value< reference_to_array >();
|
||||
spsc_queue_buffer_push_return_value< iterator_pair >();
|
||||
spsc_queue_buffer_push_return_value< span_ >();
|
||||
}
|
||||
|
||||
template < int EnqueueMode, int ElementCount, int BufferSize, int NumberOfIterations >
|
||||
@@ -240,12 +228,13 @@ void spsc_queue_buffer_push( void )
|
||||
BOOST_TEST_REQUIRE( rb.empty() );
|
||||
switch ( EnqueueMode ) {
|
||||
case pointer_and_size: BOOST_TEST_REQUIRE( rb.push( data, xqueue_size ) == xqueue_size ); break;
|
||||
|
||||
case reference_to_array: BOOST_TEST_REQUIRE( rb.push( data ) == xqueue_size ); break;
|
||||
|
||||
case iterator_pair: BOOST_TEST_REQUIRE( rb.push( data, data + xqueue_size ) == data + xqueue_size ); break;
|
||||
case span_:
|
||||
BOOST_TEST_REQUIRE( rb.push( boost::span< const int >( data, xqueue_size ) ) == xqueue_size );
|
||||
break;
|
||||
|
||||
default: assert( false );
|
||||
default: assert( false );
|
||||
}
|
||||
|
||||
int out[ xqueue_size ];
|
||||
@@ -260,6 +249,7 @@ BOOST_AUTO_TEST_CASE( spsc_queue_buffer_push_test )
|
||||
spsc_queue_buffer_push< pointer_and_size, 7, 16, 64 >();
|
||||
spsc_queue_buffer_push< reference_to_array, 7, 16, 64 >();
|
||||
spsc_queue_buffer_push< iterator_pair, 7, 16, 64 >();
|
||||
spsc_queue_buffer_push< span_, 7, 16, 64 >();
|
||||
}
|
||||
|
||||
template < int EnqueueMode, int ElementCount, int BufferSize, int NumberOfIterations >
|
||||
@@ -283,11 +273,8 @@ void spsc_queue_buffer_pop( void )
|
||||
|
||||
switch ( EnqueueMode ) {
|
||||
case pointer_and_size: BOOST_TEST_REQUIRE( rb.pop( out, xqueue_size ) == xqueue_size ); break;
|
||||
|
||||
case reference_to_array: BOOST_TEST_REQUIRE( rb.pop( out ) == xqueue_size ); break;
|
||||
|
||||
case output_iterator_: BOOST_TEST_REQUIRE( rb.pop( std::back_inserter( vout ) ) == xqueue_size ); break;
|
||||
|
||||
default: assert( false );
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <boost/lockfree/stack.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <memory>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
@@ -20,7 +20,7 @@
|
||||
BOOST_AUTO_TEST_CASE( stack_test_bounded )
|
||||
{
|
||||
typedef queue_stress_tester< true > tester_type;
|
||||
boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
|
||||
boost::lockfree::stack< long > q( 128 );
|
||||
tester->run( q );
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <boost/lockfree/stack.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
# include <boost/test/included/unit_test.hpp>
|
||||
@@ -20,8 +18,8 @@
|
||||
|
||||
BOOST_AUTO_TEST_CASE( stack_test_fixed_size )
|
||||
{
|
||||
typedef queue_stress_tester<> tester_type;
|
||||
boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
typedef queue_stress_tester<> tester_type;
|
||||
std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
|
||||
boost::lockfree::stack< long, boost::lockfree::capacity< 8 > > q;
|
||||
tester->run( q );
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cstdlib> //std::system
|
||||
#include <thread>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/lockfree/stack.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
using namespace boost::interprocess;
|
||||
typedef allocator< int, managed_shared_memory::segment_manager > ShmemAllocator;
|
||||
@@ -42,7 +42,7 @@ int main( int argc, char* argv[] )
|
||||
return 1;
|
||||
|
||||
while ( !queue->empty() )
|
||||
boost::thread::yield();
|
||||
std::this_thread::yield();
|
||||
return 0;
|
||||
} else {
|
||||
managed_shared_memory segment( open_only, "MySharedMemory" );
|
||||
|
||||
+35
-21
@@ -6,7 +6,6 @@
|
||||
|
||||
|
||||
#include <boost/lockfree/stack.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
@@ -15,8 +14,6 @@
|
||||
# include <boost/test/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
|
||||
BOOST_AUTO_TEST_CASE( simple_stack_test )
|
||||
{
|
||||
boost::lockfree::stack< long > stk( 128 );
|
||||
@@ -61,6 +58,23 @@ BOOST_AUTO_TEST_CASE( ranged_push_test )
|
||||
BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( span_push_test )
|
||||
{
|
||||
boost::lockfree::stack< long > stk( 128 );
|
||||
|
||||
long data[ 2 ] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_REQUIRE( stk.push( boost::span< const long >( data ) ) == 2 );
|
||||
|
||||
long out;
|
||||
BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) );
|
||||
BOOST_TEST_REQUIRE( out == 2 );
|
||||
BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) );
|
||||
BOOST_TEST_REQUIRE( out == 1 );
|
||||
BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( ranged_unsynchronized_push_test )
|
||||
{
|
||||
boost::lockfree::stack< long > stk( 128 );
|
||||
@@ -77,6 +91,23 @@ BOOST_AUTO_TEST_CASE( ranged_unsynchronized_push_test )
|
||||
BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( span_unsynchronized_push_test )
|
||||
{
|
||||
boost::lockfree::stack< long > stk( 128 );
|
||||
|
||||
long data[ 2 ] = { 1, 2 };
|
||||
|
||||
BOOST_TEST_REQUIRE( stk.unsynchronized_push( boost::span< const long >( data ) ) == 2 );
|
||||
|
||||
long out;
|
||||
BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) );
|
||||
BOOST_TEST_REQUIRE( out == 2 );
|
||||
BOOST_TEST_REQUIRE( stk.unsynchronized_pop( out ) );
|
||||
BOOST_TEST_REQUIRE( out == 1 );
|
||||
BOOST_TEST_REQUIRE( !stk.unsynchronized_pop( out ) );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( fixed_size_stack_test )
|
||||
{
|
||||
boost::lockfree::stack< long, boost::lockfree::capacity< 128 > > stk;
|
||||
@@ -134,18 +165,13 @@ BOOST_AUTO_TEST_CASE( stack_consume_one_test )
|
||||
f.push( 1 );
|
||||
f.push( 2 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
bool success1 = f.consume_one( test_equal( 2 ) );
|
||||
bool success2 = f.consume_one( test_equal( 1 ) );
|
||||
#else
|
||||
bool success1 = f.consume_one( []( int i ) {
|
||||
BOOST_TEST_REQUIRE( i == 2 );
|
||||
} );
|
||||
|
||||
bool success2 = f.consume_one( []( int i ) {
|
||||
bool success2 = f.consume_one( []( int i ) mutable {
|
||||
BOOST_TEST_REQUIRE( i == 1 );
|
||||
} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( success1 );
|
||||
BOOST_TEST_REQUIRE( success2 );
|
||||
@@ -163,11 +189,7 @@ BOOST_AUTO_TEST_CASE( stack_consume_all_test )
|
||||
f.push( 1 );
|
||||
f.push( 2 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
size_t consumed = f.consume_all( dummy_functor() );
|
||||
#else
|
||||
size_t consumed = f.consume_all( []( int i ) {} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( consumed == 2u );
|
||||
|
||||
@@ -185,11 +207,7 @@ BOOST_AUTO_TEST_CASE( stack_consume_all_atomic_test )
|
||||
f.push( 2 );
|
||||
f.push( 3 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
size_t consumed = f.consume_all_atomic( dummy_functor() );
|
||||
#else
|
||||
size_t consumed = f.consume_all_atomic( []( int i ) {} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( consumed == 3u );
|
||||
|
||||
@@ -208,11 +226,7 @@ BOOST_AUTO_TEST_CASE( stack_consume_all_atomic_reversed_test )
|
||||
f.push( 2 );
|
||||
f.push( 3 );
|
||||
|
||||
#ifdef BOOST_NO_CXX11_LAMBDAS
|
||||
size_t consumed = f.consume_all_atomic_reversed( dummy_functor() );
|
||||
#else
|
||||
size_t consumed = f.consume_all_atomic_reversed( []( int i ) {} );
|
||||
#endif
|
||||
|
||||
BOOST_TEST_REQUIRE( consumed == 3u );
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
#include <boost/lockfree/stack.hpp>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#ifdef BOOST_LOCKFREE_INCLUDE_TESTS
|
||||
# include <boost/test/included/unit_test.hpp>
|
||||
@@ -21,7 +19,7 @@
|
||||
BOOST_AUTO_TEST_CASE( stack_test_unbounded )
|
||||
{
|
||||
typedef queue_stress_tester< false > tester_type;
|
||||
boost::scoped_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
std::unique_ptr< tester_type > tester( new tester_type( 4, 4 ) );
|
||||
|
||||
boost::lockfree::stack< long > q( 128 );
|
||||
tester->run( q );
|
||||
|
||||
+23
-23
@@ -5,19 +5,19 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "test_helpers.hpp"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#ifdef __VXWORKS__
|
||||
# include <thread>
|
||||
#endif
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace impl {
|
||||
|
||||
using boost::array;
|
||||
using namespace boost;
|
||||
using namespace std;
|
||||
|
||||
template < bool Bounded = false >
|
||||
struct queue_stress_tester
|
||||
{
|
||||
@@ -30,13 +30,13 @@ struct queue_stress_tester
|
||||
const int reader_threads;
|
||||
const int writer_threads;
|
||||
|
||||
boost::lockfree::detail::atomic< int > writers_finished;
|
||||
std::atomic< int > writers_finished;
|
||||
|
||||
static_hashed_set< long, buckets > data;
|
||||
static_hashed_set< long, buckets > dequeued;
|
||||
array< std::set< long >, buckets > returned;
|
||||
static_hashed_set< long, buckets > data;
|
||||
static_hashed_set< long, buckets > dequeued;
|
||||
std::array< std::set< long >, buckets > returned;
|
||||
|
||||
boost::lockfree::detail::atomic< int > push_count, pop_count;
|
||||
std::atomic< int > push_count, pop_count;
|
||||
|
||||
queue_stress_tester( int reader, int writer ) :
|
||||
reader_threads( reader ),
|
||||
@@ -58,13 +58,13 @@ struct queue_stress_tester
|
||||
if ( Bounded )
|
||||
while ( stk.bounded_push( id ) == false ) {
|
||||
#ifdef __VXWORKS__
|
||||
thread::yield();
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
while ( stk.push( id ) == false ) {
|
||||
#ifdef __VXWORKS__
|
||||
thread::yield();
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
++push_count;
|
||||
@@ -72,7 +72,7 @@ struct queue_stress_tester
|
||||
writers_finished += 1;
|
||||
}
|
||||
|
||||
boost::lockfree::detail::atomic< bool > running;
|
||||
std::atomic< bool > running;
|
||||
|
||||
template < typename queue >
|
||||
bool consume_element( queue& q )
|
||||
@@ -105,7 +105,7 @@ struct queue_stress_tester
|
||||
break;
|
||||
|
||||
#ifdef __VXWORKS__
|
||||
thread::yield();
|
||||
std::this_thread::yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -119,20 +119,20 @@ struct queue_stress_tester
|
||||
BOOST_WARN( stk.is_lock_free() );
|
||||
writers_finished.store( 0 );
|
||||
|
||||
thread_group writer;
|
||||
thread_group reader;
|
||||
boost::thread_group writer;
|
||||
boost::thread_group reader;
|
||||
|
||||
BOOST_TEST_REQUIRE( stk.empty() );
|
||||
|
||||
for ( int i = 0; i != reader_threads; ++i )
|
||||
reader.create_thread( boost::bind( &queue_stress_tester::template get_items< queue >,
|
||||
this,
|
||||
boost::ref( stk ) ) );
|
||||
reader.create_thread( [ & ] {
|
||||
get_items( stk );
|
||||
} );
|
||||
|
||||
for ( int i = 0; i != writer_threads; ++i )
|
||||
writer.create_thread( boost::bind( &queue_stress_tester::template add_items< queue >,
|
||||
this,
|
||||
boost::ref( stk ) ) );
|
||||
writer.create_thread( [ & ] {
|
||||
add_items( stk );
|
||||
} );
|
||||
|
||||
std::cout << "threads created" << std::endl;
|
||||
|
||||
|
||||
+12
-14
@@ -7,18 +7,17 @@
|
||||
#ifndef BOOST_LOCKFREE_TEST_HELPERS
|
||||
#define BOOST_LOCKFREE_TEST_HELPERS
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/lockfree/detail/atomic.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <set>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
template < typename int_type >
|
||||
int_type generate_id( void )
|
||||
{
|
||||
static boost::lockfree::detail::atomic< int_type > generator( 0 );
|
||||
static std::atomic< int_type > generator( 0 );
|
||||
return ++generator;
|
||||
}
|
||||
|
||||
@@ -38,10 +37,9 @@ public:
|
||||
{
|
||||
std::size_t index = calc_index( id );
|
||||
|
||||
boost::lock_guard< boost::mutex > lock( ref_mutex[ index ] );
|
||||
std::lock_guard< std::mutex > lock( ref_mutex[ index ] );
|
||||
|
||||
std::pair< typename std::set< int_type >::iterator, bool > p;
|
||||
p = data[ index ].insert( id );
|
||||
auto p = data[ index ].insert( id );
|
||||
|
||||
return p.second;
|
||||
}
|
||||
@@ -50,7 +48,7 @@ public:
|
||||
{
|
||||
std::size_t index = calc_index( id );
|
||||
|
||||
boost::lock_guard< boost::mutex > lock( ref_mutex[ index ] );
|
||||
std::lock_guard< std::mutex > lock( ref_mutex[ index ] );
|
||||
|
||||
return data[ index ].find( id ) != data[ index ].end();
|
||||
}
|
||||
@@ -59,7 +57,7 @@ public:
|
||||
{
|
||||
std::size_t index = calc_index( id );
|
||||
|
||||
boost::lock_guard< boost::mutex > lock( ref_mutex[ index ] );
|
||||
std::lock_guard< std::mutex > lock( ref_mutex[ index ] );
|
||||
|
||||
if ( data[ index ].find( id ) != data[ index ].end() ) {
|
||||
data[ index ].erase( id );
|
||||
@@ -73,15 +71,15 @@ public:
|
||||
{
|
||||
std::size_t ret = 0;
|
||||
for ( int i = 0; i != buckets; ++i ) {
|
||||
boost::lock_guard< boost::mutex > lock( ref_mutex[ i ] );
|
||||
std::lock_guard< std::mutex > lock( ref_mutex[ i ] );
|
||||
ret += data[ i ].size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::array< std::set< int_type >, buckets > data;
|
||||
mutable boost::array< boost::mutex, buckets > ref_mutex;
|
||||
std::array< std::set< int_type >, buckets > data;
|
||||
mutable std::array< std::mutex, buckets > ref_mutex;
|
||||
};
|
||||
|
||||
struct test_equal
|
||||
|
||||
Reference in New Issue
Block a user