use std::atomic<std::size_t> instead of flag for better performance in arm; cross-platform supporting; add more test cases

This commit is contained in:
zhangyi 2018-11-30 15:13:44 +08:00
parent b3e2c80fc0
commit c8e81e2794
3 changed files with 43 additions and 23 deletions

View File

@ -16,10 +16,10 @@ struct alignas(std::max_align_t) elem_array_head {
using uc_t = std::uint16_t;
using ac_t = std::atomic<uc_t>;
std::atomic<std::size_t> lc_ { 0 }; // write spin lock flag
ac_t cc_ { 0 }; // connection counter, using for broadcast
ac_t wt_ { 0 }; // write index
std::atomic_flag lc_ ATOMIC_FLAG_INIT; // write spin lock flag
};
enum : std::size_t {
@ -93,7 +93,7 @@ public:
}
void* acquire(void) {
while (lc_.test_and_set(std::memory_order_acquire)) {
while (lc_.exchange(1, std::memory_order_acquire)) {
std::this_thread::yield();
}
elem_t* el = elem(wt_.load(std::memory_order_relaxed));
@ -114,7 +114,7 @@ public:
void commit(void* /*ptr*/) {
wt_.fetch_add(1, std::memory_order_relaxed);
lc_.clear(std::memory_order_release);
lc_.store(0, std::memory_order_release);
}
uc_t cursor(void) const {

View File

@ -84,8 +84,27 @@ public:
return old;
}
bool push(T const & item) {
if (elems_ == nullptr) return false;
auto ptr = elems_->acquire();
::new (ptr) T(item);
elems_->commit(ptr);
return true;
}
template <typename P>
auto push(P&& param) // disable this if P is the same as T
-> std::enable_if_t<!std::is_same<std::remove_reference_t<P>, T>::value, bool> {
if (elems_ == nullptr) return false;
auto ptr = elems_->acquire();
::new (ptr) T { std::forward<P>(param) };
elems_->commit(ptr);
return true;
}
template <typename... P>
bool push(P&&... params) {
auto push(P&&... params) // some old compilers are not support this well
-> std::enable_if_t<(sizeof...(P) != 1), bool> {
if (elems_ == nullptr) return false;
auto ptr = elems_->acquire();
::new (ptr) T { std::forward<P>(params)... };

View File

@ -293,41 +293,42 @@ void Unit::test_prod_cons_3v1(void) {
test_prod_cons<3, 1>();
}
template <int B, int E>
struct test_cons_performance {
template <int P, int C>
struct test_performance {
static void start(void) {
test_prod_cons<1, B, false>();
test_cons_performance<B + 1, E>::start();
test_performance<P - 1, C - 1>::start();
test_prod_cons<P, C, false>();
}
};
template <int E>
struct test_cons_performance<E, E> {
template <int C>
struct test_performance<1, C> {
static void start(void) {
test_prod_cons<1, E, false>();
test_performance<1, C - 1>::start();
test_prod_cons<1, C, false>();
}
};
template <int B, int E>
struct test_prod_performance {
template <int P>
struct test_performance<P, 1> {
static void start(void) {
test_prod_cons<B, 1, false>();
test_prod_performance<B + 1, E>::start();
test_performance<P - 1, 1>::start();
test_prod_cons<P, 1, false>();
}
};
template <int E>
struct test_prod_performance<E, E> {
template <>
struct test_performance<1, 1> {
static void start(void) {
test_prod_cons<E, 1, false>();
test_prod_cons<1, 1, false>();
}
};
void Unit::test_prod_cons_performance(void) {
test_cons_performance<1, 10>::start();
test_prod_performance<1, 10>::start();
test_prod_cons<3, 3, false>(); // just test
test_prod_cons<5, 5>(); // test & verify
test_performance<1 , 10>::start();
test_performance<10, 1 >::start();
test_performance<10, 10>::start();
test_prod_cons <3 , 3 >(); // test & verify
}
void Unit::test_queue(void) {