Skip to content

Commit

Permalink
prototype spsc_value
Browse files Browse the repository at this point in the history
  • Loading branch information
timblechmann committed Dec 3, 2023
1 parent bd126df commit 16a8d62
Show file tree
Hide file tree
Showing 9 changed files with 592 additions and 42 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ add_library(Boost::lockfree ALIAS boost_lockfree)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.23)
set(Headers
include/boost/lockfree/spsc_queue.hpp
include/boost/lockfree/spsc_value.hpp
include/boost/lockfree/policies.hpp
include/boost/lockfree/queue.hpp
include/boost/lockfree/lockfree_forward.hpp
Expand Down
33 changes: 12 additions & 21 deletions doc/lockfree.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ lock-freedom:

[h2 Data Structures]

_lockfree_ implements three lock-free data structures:
_lockfree_ implements four lock-free data structures:

[variablelist
[[[classref boost::lockfree::queue]]
Expand All @@ -129,6 +129,10 @@ _lockfree_ implements three lock-free data structures:
[[[classref boost::lockfree::spsc_queue]]
[a wait-free single-producer/single-consumer queue (commonly known as ringbuffer)]
]

[[[classref boost::lockfree::spsc_value]]
[a wait-free single-producer/single-consumer value (commonly known as triple buffer)]
]
]

[h3 Data Structure Configuration]
Expand All @@ -150,7 +154,11 @@ The data structures can be configured with [@boost:/libs/parameter/doc/html/inde
]

[[[classref boost::lockfree::allocator]]
[Defines the allocator. _lockfree_ supports stateful allocator and is compatible with [@boost:/libs/interprocess/index.html Boost.Interprocess] allocators.]
[Defines the allocator.]
]

[[[classref boost::lockfree::allow_multiple_reads]]
[Configures the [classref boost::lockfree::spsc_value] to allow the content to be read multiple times.]
]
]

Expand All @@ -161,7 +169,7 @@ The data structures can be configured with [@boost:/libs/parameter/doc/html/inde

[h2 Queue]

The [classref boost::lockfree::queue boost::lockfree::queue] class implements a multi-writer/multi-reader queue. The
The [classref boost::lockfree::queue] class implements a multi-writer/multi-reader queue. The
following example shows how integer values are produced and consumed by 4 threads each:

[import ../examples/queue.cpp]
Expand All @@ -177,7 +185,7 @@ consumed 40000000 objects.

[h2 Stack]

The [classref boost::lockfree::stack boost::lockfree::stack] class implements a multi-writer/multi-reader stack. The
The [classref boost::lockfree::stack] class implements a multi-writer/multi-reader stack. The
following example shows how integer values are produced and consumed by 4 threads each:

[import ../examples/stack.cpp]
Expand Down Expand Up @@ -212,16 +220,6 @@ consumed 10000000 objects.

[section Rationale]

[section Data Structures]

The implementations are implementations of well-known data structures. The queue is based on
[@http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.3574 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Michael Scott and Maged Michael],
the stack is based on [@http://books.google.com/books?id=YQg3HAAACAAJ Systems programming: coping with parallelism by R. K. Treiber]
and the spsc_queue is considered as 'folklore' and is implemented in several open-source projects including the linux kernel. All
data structures are discussed in detail in [@http://books.google.com/books?id=pFSwuqtJgxYC "The Art of Multiprocessor Programming" by Herlihy & Shavit].

[endsect]

[section Memory Management]

The lock-free [classref boost::lockfree::queue] and [classref boost::lockfree::stack] classes are node-based data structures,
Expand Down Expand Up @@ -274,13 +272,6 @@ _lockfree_ requires a c++14 compliant compiler

[endsect]

[section Future Developments]

* More data structures (set, hash table, dequeue)
* Backoff schemes (exponential backoff or elimination)

[endsect]

[section References]

# [@http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.3574 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Michael Scott and Maged Michael],
Expand Down
21 changes: 13 additions & 8 deletions include/boost/lockfree/detail/parameter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ namespace boost { namespace lockfree { namespace detail {
template < typename bound_args, typename tag_type, typename default_ >
using extract_arg_or_default_t = typename parameter::binding< bound_args, tag_type, default_ >::type;


template < typename BoundArgs, typename TypeTag, typename IntegralType, IntegralType default_ = IntegralType {} >
struct extract_integral_arg_or_default_t
{
static constexpr IntegralType value
= extract_arg_or_default_t< BoundArgs, TypeTag, std::integral_constant< IntegralType, default_ > >::value;
};


struct no_such_parameter_t
{};

Expand Down Expand Up @@ -65,20 +74,16 @@ using extract_allocator_t = typename extract_allocator< bound_args, T >::type;
//----------------------------------------------------------------------------------------------------------------------

template < typename bound_args, bool default_ = false >
struct extract_fixed_sized
{
using capacity_t
= extract_arg_or_default_t< bound_args, tag::fixed_sized, std::integral_constant< bool, default_ > >;
using extract_fixed_sized = extract_integral_arg_or_default_t< bound_args, tag::fixed_sized, bool, default_ >;

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;
using extract_allow_multiple_reads
= extract_integral_arg_or_default_t< bound_args, tag::allow_multiple_reads, bool, default_ >;

//----------------------------------------------------------------------------------------------------------------------


}}} // namespace boost::lockfree::detail

#endif /* BOOST_LOCKFREE_DETAIL_PARAMETER_HPP */
4 changes: 4 additions & 0 deletions include/boost/lockfree/lockfree_forward.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ template < typename T, typename... Options >
requires( std::is_default_constructible_v< T >, std::is_move_assignable_v< T > || std::is_copy_assignable_v< T > )
# endif
class spsc_queue;

template < typename T, typename... Options >
struct spsc_value;

}} // namespace boost::lockfree

#endif // BOOST_DOXYGEN_INVOKED
Expand Down
27 changes: 14 additions & 13 deletions include/boost/lockfree/policies.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,26 @@ namespace tag {
struct allocator;
struct fixed_sized;
struct capacity;
struct allow_multiple_reads;
} // namespace tag

/** Configures a data structure as \b fixed-sized.
*
* The internal nodes are stored inside an array and they are addressed by array indexing. This limits the possible
* size of the queue to the number of elements that can be addressed by the index type (usually 2**16-2), but on
* platforms that lack double-width compare-and-exchange instructions, this is the best way to achieve lock-freedom.
* This implies that a data structure is bounded.
* */
template < 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.
*
* This implies that a data structure is bounded and fixed-sized.
* */
template < 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.
* */
template < class Alloc >
struct allocator : boost::parameter::template_keyword< tag::allocator, Alloc >
{};

template < bool AllowMultipleReads >
struct allow_multiple_reads :
boost::parameter::template_keyword< tag::allow_multiple_reads, std::integral_constant< bool, AllowMultipleReads > >
{};

#else

/** Configures a data structure as \b fixed-sized.
Expand All @@ -71,6 +64,14 @@ struct capacity;
template < class Alloc >
struct allocator;

/** Configures the spsc_value to consume the value multiple times
*
* Caveats:
* * one cannot move the value out
* */
template < bool AllowMultipleReads >
struct allow_multiple_reads;

#endif

}} // namespace boost::lockfree
Expand Down
Loading

0 comments on commit 16a8d62

Please sign in to comment.