considering a different implementation, may have bugs

This commit is contained in:
mutouyun 2018-12-13 18:37:06 +08:00
parent a26f171124
commit 96c2a037f3
4 changed files with 60 additions and 11 deletions

View File

@ -17,6 +17,7 @@ struct uint;
template <> struct uint<8 > { using type = std::uint8_t ; }; template <> struct uint<8 > { using type = std::uint8_t ; };
template <> struct uint<16> { using type = std::uint16_t; }; template <> struct uint<16> { using type = std::uint16_t; };
template <> struct uint<32> { using type = std::uint32_t; }; template <> struct uint<32> { using type = std::uint32_t; };
template <> struct uint<64> { using type = std::uint64_t; };
template <std::size_t N> template <std::size_t N>
using uint_t = typename uint<N>::type; using uint_t = typename uint<N>::type;

View File

@ -2,12 +2,13 @@
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include <type_traits>
#include "def.h" #include "def.h"
namespace ipc { namespace ipc {
class rw_lock { class rw_cas_lock {
std::atomic_size_t lc_ { 0 }; std::atomic_size_t lc_ { 0 };
enum : std::size_t { enum : std::size_t {
@ -18,7 +19,7 @@ public:
void lock() { void lock() {
for (unsigned k = 0;; ++k) { for (unsigned k = 0;; ++k) {
std::size_t expected = 0; std::size_t expected = 0;
if (lc_.compare_exchange_weak(expected, w_flag, std::memory_order_acq_rel)) { if (lc_.compare_exchange_weak(expected, w_flag, std::memory_order_acquire)) {
break; break;
} }
yield(k); yield(k);
@ -34,7 +35,52 @@ public:
std::size_t old = lc_.load(std::memory_order_relaxed); std::size_t old = lc_.load(std::memory_order_relaxed);
std::size_t unlocked = old + 1; std::size_t unlocked = old + 1;
if (unlocked && if (unlocked &&
lc_.compare_exchange_weak(old, unlocked, std::memory_order_acq_rel)) { lc_.compare_exchange_weak(old, unlocked, std::memory_order_acquire)) {
break;
}
yield(k);
std::atomic_thread_fence(std::memory_order_acquire);
}
}
void unlock_shared() {
lc_.fetch_sub(1, std::memory_order_release);
}
};
class rw_lock {
using lc_ui_t = std::size_t;
std::atomic<lc_ui_t> lc_ { 0 };
enum : lc_ui_t {
w_mask = (std::numeric_limits<std::make_signed_t<lc_ui_t>>::max)(), // b 0111 1111
w_flag = w_mask + 1 // b 1000 0000
};
public:
void lock() {
auto old = lc_.fetch_or(w_flag, std::memory_order_acquire);
if (!old) return;
// just like a spin-lock
if (old & w_flag) for (unsigned k = 1; lc_.fetch_or(w_flag, std::memory_order_acquire) & w_flag; ++k) {
yield(k);
}
// wait for reading finished
else for (unsigned k = 1; lc_.load(std::memory_order_acquire) & w_mask; ++k) {
yield(k);
}
}
void unlock() {
lc_.fetch_and(w_mask, std::memory_order_release);
}
void lock_shared() {
for (unsigned k = 0;; ++k) {
auto old = lc_.load(std::memory_order_relaxed);
// if w_flag set, just continue; otherwise cas ++
if (!(old & w_flag) &&
lc_.compare_exchange_weak(old, old + 1, std::memory_order_acquire)) {
break; break;
} }
yield(k); yield(k);

View File

@ -31,7 +31,7 @@ private slots:
void test_prod_cons_performance(); void test_prod_cons_performance();
void test_queue(); void test_queue();
} unit__; } /*unit__*/;
#include "test_circ.moc" #include "test_circ.moc"

View File

@ -101,6 +101,7 @@ void benchmark() {
{ {
std::unique_lock<Lc> guard { lc }; std::unique_lock<Lc> guard { lc };
datas.push_back(i); datas.push_back(i);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} }
std::this_thread::yield(); std::this_thread::yield();
} }
@ -122,16 +123,17 @@ void test_performance() {
<< std::endl; << std::endl;
benchmark<ipc::rw_lock , W, R>(); benchmark<ipc::rw_lock , W, R>();
benchmark<lc_wrapper<capo::spin_lock>, W, R>(); // benchmark<ipc::rw_cas_lock , W, R>();
benchmark<lc_wrapper<std::mutex> , W, R>(); // benchmark<lc_wrapper<capo::spin_lock>, W, R>();
benchmark<std::shared_timed_mutex , W, R>(); // benchmark<lc_wrapper<std::mutex> , W, R>();
// benchmark<std::shared_timed_mutex , W, R>();
} }
void Unit::test_rw_lock() { void Unit::test_rw_lock() {
test_performance<1, 1>(); test_performance<2, 1>();
test_performance<4, 4>(); // test_performance<4, 4>();
test_performance<1, 8>(); // test_performance<1, 8>();
test_performance<8, 1>(); // test_performance<8, 1>();
} }
void Unit::test_send_recv() { void Unit::test_send_recv() {