mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
upd: [concur] context => header
This commit is contained in:
parent
7e1f9f306e
commit
bb67bd9ddc
@ -44,26 +44,26 @@ class broadcast {};
|
|||||||
|
|
||||||
/// \brief Determines whether type T can be implicitly converted to type U.
|
/// \brief Determines whether type T can be implicitly converted to type U.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
using is_convertible = typename std::enable_if<std::is_convertible<T *, U *>::value>::type;
|
using is_convertible = std::enable_if_t<std::is_convertible<T *, U *>::value, bool>;
|
||||||
|
|
||||||
/// \brief Check whether the context type is valid.
|
/// \brief Check whether the elems header type is valid.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using is_context = decltype(typename std::enable_if<std::is_convertible<decltype(
|
using is_elems_header = decltype(
|
||||||
std::declval<T>().valid()), bool>::value>::type(),
|
std::declval<index_t>() % std::declval<T>().circ_size,
|
||||||
std::declval<index_t>() % std::declval<T>().circ_size);
|
std::enable_if_t<std::is_convertible<decltype(std::declval<T>().valid()), bool>::value, bool>{});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Calculate the corresponding queue position modulo the index value.
|
* \brief Calculate the corresponding queue position modulo the index value.
|
||||||
*
|
*
|
||||||
* \tparam C a context type
|
* \tparam H a elems header type
|
||||||
* \param ctx a context object
|
* \param hdr a elems header object
|
||||||
* \param idx a context array index
|
* \param idx a elems array index
|
||||||
* \return index_t - a corresponding queue position
|
* \return index_t - a corresponding queue position
|
||||||
*/
|
*/
|
||||||
template <typename C, typename = is_context<C>>
|
template <typename H, is_elems_header<H> = true>
|
||||||
constexpr index_t trunc_index(C const &ctx, index_t idx) noexcept {
|
constexpr index_t trunc_index(H const &hdr, index_t idx) noexcept {
|
||||||
// `circ_size == 2^N` => `idx & (circ_size - 1)`
|
// `circ_size == 2^N` => `idx & (circ_size - 1)`
|
||||||
return ctx.valid() ? (idx % ctx.circ_size) : 0;
|
return hdr.valid() ? (idx % hdr.circ_size) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Producer algorithm implementation.
|
/// \brief Producer algorithm implementation.
|
||||||
@ -86,17 +86,17 @@ struct consumer;
|
|||||||
template <>
|
template <>
|
||||||
struct producer<trans::unicast, relation::single> {
|
struct producer<trans::unicast, relation::single> {
|
||||||
|
|
||||||
struct context_impl {
|
struct header_impl {
|
||||||
index_t w_idx {0}; ///< write index
|
index_t w_idx {0}; ///< write index
|
||||||
private: padding<decltype(w_idx)> ___;
|
private: padding<decltype(w_idx)> ___;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename C, typename U,
|
template <typename T, typename H, typename U,
|
||||||
typename = is_context<C>,
|
is_elems_header<H> = true,
|
||||||
typename = is_convertible<C, context_impl>>
|
is_convertible<H, header_impl> = true>
|
||||||
static bool enqueue(::LIBIMP::span<element<T>> elems, C &ctx, U &&src) noexcept {
|
static bool enqueue(::LIBIMP::span<element<T>> elems, H &hdr, U &&src) noexcept {
|
||||||
auto w_idx = ctx.w_idx;
|
auto w_idx = hdr.w_idx;
|
||||||
auto w_cur = trunc_index(ctx, w_idx);
|
auto w_cur = trunc_index(hdr, w_idx);
|
||||||
auto &elem = elems[w_cur];
|
auto &elem = elems[w_cur];
|
||||||
auto f_ct = elem.get_flag();
|
auto f_ct = elem.get_flag();
|
||||||
// Verify index.
|
// Verify index.
|
||||||
@ -105,7 +105,7 @@ struct producer<trans::unicast, relation::single> {
|
|||||||
return false; // full
|
return false; // full
|
||||||
}
|
}
|
||||||
// Get a valid index and iterate backwards.
|
// Get a valid index and iterate backwards.
|
||||||
ctx.w_idx += 1;
|
hdr.w_idx += 1;
|
||||||
// Set data & flag.
|
// Set data & flag.
|
||||||
elem.set_data(std::forward<U>(src));
|
elem.set_data(std::forward<U>(src));
|
||||||
elem.set_flag(static_cast<index_t>(~w_idx));
|
elem.set_flag(static_cast<index_t>(~w_idx));
|
||||||
@ -117,18 +117,18 @@ struct producer<trans::unicast, relation::single> {
|
|||||||
template <>
|
template <>
|
||||||
struct producer<trans::unicast, relation::multi> {
|
struct producer<trans::unicast, relation::multi> {
|
||||||
|
|
||||||
struct context_impl {
|
struct header_impl {
|
||||||
std::atomic<index_t> w_idx {0}; ///< write index
|
std::atomic<index_t> w_idx {0}; ///< write index
|
||||||
private: padding<decltype(w_idx)> ___;
|
private: padding<decltype(w_idx)> ___;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename C, typename U,
|
template <typename T, typename H, typename U,
|
||||||
typename = is_context<C>,
|
is_elems_header<H> = true,
|
||||||
typename = is_convertible<C, context_impl>>
|
is_convertible<H, header_impl> = true>
|
||||||
static bool enqueue(::LIBIMP::span<element<T>> elems, C &ctx, U &&src) noexcept {
|
static bool enqueue(::LIBIMP::span<element<T>> elems, H &hdr, U &&src) noexcept {
|
||||||
auto w_idx = ctx.w_idx.load(std::memory_order_acquire);
|
auto w_idx = hdr.w_idx.load(std::memory_order_acquire);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto w_cur = trunc_index(ctx, w_idx);
|
auto w_cur = trunc_index(hdr, w_idx);
|
||||||
auto &elem = elems[w_cur];
|
auto &elem = elems[w_cur];
|
||||||
auto f_ct = elem.get_flag();
|
auto f_ct = elem.get_flag();
|
||||||
// Verify index.
|
// Verify index.
|
||||||
@ -137,7 +137,7 @@ struct producer<trans::unicast, relation::multi> {
|
|||||||
return false; // full
|
return false; // full
|
||||||
}
|
}
|
||||||
// Get a valid index and iterate backwards.
|
// Get a valid index and iterate backwards.
|
||||||
if (!ctx.w_idx.compare_exchange_weak(w_idx, w_idx + 1, std::memory_order_acq_rel)) {
|
if (!hdr.w_idx.compare_exchange_weak(w_idx, w_idx + 1, std::memory_order_acq_rel)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Set data & flag.
|
// Set data & flag.
|
||||||
@ -152,17 +152,17 @@ struct producer<trans::unicast, relation::multi> {
|
|||||||
template <>
|
template <>
|
||||||
struct consumer<trans::unicast, relation::single> {
|
struct consumer<trans::unicast, relation::single> {
|
||||||
|
|
||||||
struct context_impl {
|
struct header_impl {
|
||||||
index_t r_idx {0}; ///< read index
|
index_t r_idx {0}; ///< read index
|
||||||
private: padding<decltype(r_idx)> ___;
|
private: padding<decltype(r_idx)> ___;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename C, typename U,
|
template <typename T, typename H, typename U,
|
||||||
typename = is_context<C>,
|
is_elems_header<H> = true,
|
||||||
typename = is_convertible<C, context_impl>>
|
is_convertible<H, header_impl> = true>
|
||||||
static bool dequeue(::LIBIMP::span<element<T>> elems, C &ctx, U &des) noexcept {
|
static bool dequeue(::LIBIMP::span<element<T>> elems, H &hdr, U &des) noexcept {
|
||||||
auto r_idx = ctx.r_idx;
|
auto r_idx = hdr.r_idx;
|
||||||
auto r_cur = trunc_index(ctx, r_idx);
|
auto r_cur = trunc_index(hdr, r_idx);
|
||||||
auto &elem = elems[r_cur];
|
auto &elem = elems[r_cur];
|
||||||
auto f_ct = elem.get_flag();
|
auto f_ct = elem.get_flag();
|
||||||
// Verify index.
|
// Verify index.
|
||||||
@ -170,7 +170,7 @@ struct consumer<trans::unicast, relation::single> {
|
|||||||
return false; // empty
|
return false; // empty
|
||||||
}
|
}
|
||||||
// Get a valid index and iterate backwards.
|
// Get a valid index and iterate backwards.
|
||||||
ctx.r_idx += 1;
|
hdr.r_idx += 1;
|
||||||
// Get data & set flag.
|
// Get data & set flag.
|
||||||
des = LIBCONCUR::get(elem);
|
des = LIBCONCUR::get(elem);
|
||||||
elem.set_flag(r_idx + static_cast<index_t>(elems.size())/*avoid overflow*/);
|
elem.set_flag(r_idx + static_cast<index_t>(elems.size())/*avoid overflow*/);
|
||||||
@ -182,18 +182,18 @@ struct consumer<trans::unicast, relation::single> {
|
|||||||
template <>
|
template <>
|
||||||
struct consumer<trans::unicast, relation::multi> {
|
struct consumer<trans::unicast, relation::multi> {
|
||||||
|
|
||||||
struct context_impl {
|
struct header_impl {
|
||||||
std::atomic<index_t> r_idx {0}; ///< read index
|
std::atomic<index_t> r_idx {0}; ///< read index
|
||||||
private: padding<decltype(r_idx)> ___;
|
private: padding<decltype(r_idx)> ___;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename C, typename U,
|
template <typename T, typename H, typename U,
|
||||||
typename = is_context<C>,
|
is_elems_header<H> = true,
|
||||||
typename = is_convertible<C, context_impl>>
|
is_convertible<H, header_impl> = true>
|
||||||
static bool dequeue(::LIBIMP::span<element<T>> elems, C &ctx, U &des) noexcept {
|
static bool dequeue(::LIBIMP::span<element<T>> elems, H &hdr, U &des) noexcept {
|
||||||
auto r_idx = ctx.r_idx.load(std::memory_order_acquire);
|
auto r_idx = hdr.r_idx.load(std::memory_order_acquire);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto r_cur = trunc_index(ctx, r_idx);
|
auto r_cur = trunc_index(hdr, r_idx);
|
||||||
auto &elem = elems[r_cur];
|
auto &elem = elems[r_cur];
|
||||||
auto f_ct = elem.get_flag();
|
auto f_ct = elem.get_flag();
|
||||||
// Verify index.
|
// Verify index.
|
||||||
@ -201,7 +201,7 @@ struct consumer<trans::unicast, relation::multi> {
|
|||||||
return false; // empty
|
return false; // empty
|
||||||
}
|
}
|
||||||
// Get a valid index and iterate backwards.
|
// Get a valid index and iterate backwards.
|
||||||
if (!ctx.r_idx.compare_exchange_weak(r_idx, r_idx + 1, std::memory_order_acq_rel)) {
|
if (!hdr.r_idx.compare_exchange_weak(r_idx, r_idx + 1, std::memory_order_acq_rel)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Get data & set flag.
|
// Get data & set flag.
|
||||||
@ -227,7 +227,7 @@ struct producer<trans::broadcast, relation::multi> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Multi-read consumer model implementation.
|
/// \brief Multi-read consumer model implementation.
|
||||||
// Single-read consumer model is not required.
|
/// Single-read consumer model is not required.
|
||||||
template <>
|
template <>
|
||||||
struct consumer<trans::broadcast, relation::multi> {
|
struct consumer<trans::broadcast, relation::multi> {
|
||||||
};
|
};
|
||||||
@ -243,16 +243,16 @@ template <typename TransModT, typename ProdModT, typename ConsModT>
|
|||||||
struct prod_cons : producer<TransModT, ProdModT>
|
struct prod_cons : producer<TransModT, ProdModT>
|
||||||
, consumer<TransModT, ConsModT> {
|
, consumer<TransModT, ConsModT> {
|
||||||
|
|
||||||
/// \brief Mixing producer and consumer context definitions.
|
/// \brief Mixing producer and consumer header definitions.
|
||||||
struct context : producer<TransModT, ProdModT>::context_impl
|
struct header : producer<TransModT, ProdModT>::header_impl
|
||||||
, consumer<TransModT, ConsModT>::context_impl {
|
, consumer<TransModT, ConsModT>::header_impl {
|
||||||
index_t const circ_size;
|
index_t const circ_size;
|
||||||
|
|
||||||
constexpr context(index_t cs) noexcept
|
constexpr header(index_t cs) noexcept
|
||||||
: circ_size(cs) {}
|
: circ_size(cs) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr context(::LIBIMP::span<element<T>> elems) noexcept
|
constexpr header(::LIBIMP::span<element<T>> elems) noexcept
|
||||||
: circ_size(static_cast<index_t>(elems.size())) {}
|
: circ_size(static_cast<index_t>(elems.size())) {}
|
||||||
|
|
||||||
constexpr bool valid() const noexcept {
|
constexpr bool valid() const noexcept {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ TEST(concurrent, index_and_flag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(concurrent, trunc_index) {
|
TEST(concurrent, trunc_index) {
|
||||||
struct context {
|
struct header {
|
||||||
concur::index_t circ_size;
|
concur::index_t circ_size;
|
||||||
|
|
||||||
bool valid() const noexcept {
|
bool valid() const noexcept {
|
||||||
@ -32,60 +32,60 @@ TEST(concurrent, trunc_index) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// @brief circ-size = 0
|
/// @brief circ-size = 0
|
||||||
EXPECT_EQ(concur::trunc_index(context{0}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{0}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{0}, 1), 0);
|
EXPECT_EQ(concur::trunc_index(header{0}, 1), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{0}, 2), 0);
|
EXPECT_EQ(concur::trunc_index(header{0}, 2), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{0}, 16), 0);
|
EXPECT_EQ(concur::trunc_index(header{0}, 16), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{0}, 111), 0);
|
EXPECT_EQ(concur::trunc_index(header{0}, 111), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{0}, -1), 0);
|
EXPECT_EQ(concur::trunc_index(header{0}, -1), 0);
|
||||||
|
|
||||||
/// @brief circ-size = 1
|
/// @brief circ-size = 1
|
||||||
EXPECT_EQ(concur::trunc_index(context{1}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{1}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{1}, 1), 0);
|
EXPECT_EQ(concur::trunc_index(header{1}, 1), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{1}, 2), 0);
|
EXPECT_EQ(concur::trunc_index(header{1}, 2), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{1}, 16), 0);
|
EXPECT_EQ(concur::trunc_index(header{1}, 16), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{1}, 111), 0);
|
EXPECT_EQ(concur::trunc_index(header{1}, 111), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{1}, -1), 0);
|
EXPECT_EQ(concur::trunc_index(header{1}, -1), 0);
|
||||||
|
|
||||||
/// @brief circ-size = 2
|
/// @brief circ-size = 2
|
||||||
EXPECT_EQ(concur::trunc_index(context{2}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{2}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2}, 1), 1);
|
EXPECT_EQ(concur::trunc_index(header{2}, 1), 1);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2}, 2), 0);
|
EXPECT_EQ(concur::trunc_index(header{2}, 2), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2}, 16), 0);
|
EXPECT_EQ(concur::trunc_index(header{2}, 16), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2}, 111), 1);
|
EXPECT_EQ(concur::trunc_index(header{2}, 111), 1);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2}, -1), 1);
|
EXPECT_EQ(concur::trunc_index(header{2}, -1), 1);
|
||||||
|
|
||||||
/// @brief circ-size = 10
|
/// @brief circ-size = 10
|
||||||
EXPECT_EQ(concur::trunc_index(context{10}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{10}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{10}, 1), 0);
|
EXPECT_EQ(concur::trunc_index(header{10}, 1), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{10}, 2), 0);
|
EXPECT_EQ(concur::trunc_index(header{10}, 2), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{10}, 16), 0);
|
EXPECT_EQ(concur::trunc_index(header{10}, 16), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{10}, 111), 0);
|
EXPECT_EQ(concur::trunc_index(header{10}, 111), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{10}, -1), 0);
|
EXPECT_EQ(concur::trunc_index(header{10}, -1), 0);
|
||||||
|
|
||||||
/// @brief circ-size = 16
|
/// @brief circ-size = 16
|
||||||
EXPECT_EQ(concur::trunc_index(context{16}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{16}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{16}, 1), 1);
|
EXPECT_EQ(concur::trunc_index(header{16}, 1), 1);
|
||||||
EXPECT_EQ(concur::trunc_index(context{16}, 2), 2);
|
EXPECT_EQ(concur::trunc_index(header{16}, 2), 2);
|
||||||
EXPECT_EQ(concur::trunc_index(context{16}, 16), 0);
|
EXPECT_EQ(concur::trunc_index(header{16}, 16), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{16}, 111), 15);
|
EXPECT_EQ(concur::trunc_index(header{16}, 111), 15);
|
||||||
EXPECT_EQ(concur::trunc_index(context{16}, -1), 15);
|
EXPECT_EQ(concur::trunc_index(header{16}, -1), 15);
|
||||||
|
|
||||||
/// @brief circ-size = (index_t)-1
|
/// @brief circ-size = (index_t)-1
|
||||||
EXPECT_EQ(concur::trunc_index(context{(concur::index_t)-1}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{(concur::index_t)-1}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{(concur::index_t)-1}, 1), 0);
|
EXPECT_EQ(concur::trunc_index(header{(concur::index_t)-1}, 1), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{(concur::index_t)-1}, 2), 0);
|
EXPECT_EQ(concur::trunc_index(header{(concur::index_t)-1}, 2), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{(concur::index_t)-1}, 16), 0);
|
EXPECT_EQ(concur::trunc_index(header{(concur::index_t)-1}, 16), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{(concur::index_t)-1}, 111), 0);
|
EXPECT_EQ(concur::trunc_index(header{(concur::index_t)-1}, 111), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{(concur::index_t)-1}, -1), 0);
|
EXPECT_EQ(concur::trunc_index(header{(concur::index_t)-1}, -1), 0);
|
||||||
|
|
||||||
/// @brief circ-size = 2147483648 (2^31)
|
/// @brief circ-size = 2147483648 (2^31)
|
||||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, 0), 0);
|
EXPECT_EQ(concur::trunc_index(header{2147483648u}, 0), 0);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, 1), 1);
|
EXPECT_EQ(concur::trunc_index(header{2147483648u}, 1), 1);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, 2), 2);
|
EXPECT_EQ(concur::trunc_index(header{2147483648u}, 2), 2);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, 16), 16);
|
EXPECT_EQ(concur::trunc_index(header{2147483648u}, 16), 16);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, 111), 111);
|
EXPECT_EQ(concur::trunc_index(header{2147483648u}, 111), 111);
|
||||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, -1), 2147483647);
|
EXPECT_EQ(concur::trunc_index(header{2147483648u}, -1), 2147483647);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -99,7 +99,7 @@ void test_concur(std::size_t np, std::size_t nc, std::size_t k) {
|
|||||||
|
|
||||||
concur::element<std::uint64_t> circ[32] {};
|
concur::element<std::uint64_t> circ[32] {};
|
||||||
PC pc;
|
PC pc;
|
||||||
typename PC::context ctx {imp::make_span(circ)};
|
typename PC::header ctx {imp::make_span(circ)};
|
||||||
ASSERT_TRUE(ctx.valid());
|
ASSERT_TRUE(ctx.valid());
|
||||||
|
|
||||||
std::atomic<std::uint64_t> sum {0};
|
std::atomic<std::uint64_t> sum {0};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user