Refactor shared-spin-lock to use atomic "spinLock"

This commit is contained in:
Stephen Seo 2023-10-18 22:28:40 +09:00
parent d1354b13d5
commit a0f8bf0b41
2 changed files with 119 additions and 57 deletions

View file

@ -18,77 +18,121 @@ UDPC::SharedSpinLock::Ptr UDPC::SharedSpinLock::newInstance() {
UDPC::SharedSpinLock::SharedSpinLock() : UDPC::SharedSpinLock::SharedSpinLock() :
selfWeakPtr(), selfWeakPtr(),
mutex(), spinLock(false),
read(0), read(0),
write(false) write(false)
{} {}
UDPC::LockObj<false> UDPC::SharedSpinLock::spin_read_lock() { UDPC::LockObj<false> UDPC::SharedSpinLock::spin_read_lock() {
bool expected;
while (true) { while (true) {
std::lock_guard<std::mutex> lock(mutex); expected = false;
if (!write) { if(spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
++read; if (!write) {
return LockObj<false>(selfWeakPtr, Badge{}); ++read;
spinLock.store(false, std::memory_order_release);
return LockObj<false>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
} }
} }
UDPC::LockObj<false> UDPC::SharedSpinLock::try_spin_read_lock() { UDPC::LockObj<false> UDPC::SharedSpinLock::try_spin_read_lock() {
std::lock_guard<std::mutex> lock(mutex); bool expected = false;
if (!write) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
++read; if (!write) {
return LockObj<false>(selfWeakPtr, Badge{}); ++read;
spinLock.store(false, std::memory_order_release);
return LockObj<false>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
return LockObj<false>{}; return LockObj<false>{};
} }
void UDPC::SharedSpinLock::read_unlock(UDPC::Badge &&badge) { void UDPC::SharedSpinLock::read_unlock(UDPC::Badge &&badge) {
if (badge.isValid) { if (badge.isValid) {
std::lock_guard<std::mutex> lock(mutex); bool expected;
if (read > 0) { while (true) {
--read; expected = false;
badge.isValid = false; if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
if (read > 0) {
--read;
badge.isValid = false;
}
spinLock.store(false, std::memory_order_release);
break;
}
} }
} }
} }
UDPC::LockObj<true> UDPC::SharedSpinLock::spin_write_lock() { UDPC::LockObj<true> UDPC::SharedSpinLock::spin_write_lock() {
bool expected;
while (true) { while (true) {
std::lock_guard<std::mutex> lock(mutex); expected = false;
if (!write && read == 0) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
write = true; if (!write && read == 0) {
return LockObj<true>(selfWeakPtr, Badge{}); write = true;
spinLock.store(false, std::memory_order_release);
return LockObj<true>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
} }
} }
UDPC::LockObj<true> UDPC::SharedSpinLock::try_spin_write_lock() { UDPC::LockObj<true> UDPC::SharedSpinLock::try_spin_write_lock() {
std::lock_guard<std::mutex> lock(mutex); bool expected = false;
if (!write && read == 0) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
write = true; if (!write && read == 0) {
return LockObj<true>(selfWeakPtr, Badge{}); write = true;
spinLock.store(false, std::memory_order_release);
return LockObj<true>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
return LockObj<true>{}; return LockObj<true>{};
} }
void UDPC::SharedSpinLock::write_unlock(UDPC::Badge &&badge) { void UDPC::SharedSpinLock::write_unlock(UDPC::Badge &&badge) {
if (badge.isValid) { if (badge.isValid) {
std::lock_guard<std::mutex> lock(mutex); bool expected;
write = false; while(true) {
badge.isValid = false; expected = false;
if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
if (write) {
write = false;
badge.isValid = false;
}
spinLock.store(false, std::memory_order_release);
break;
}
}
} }
} }
UDPC::LockObj<false> UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) { UDPC::LockObj<false> UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) {
if (lockObj.isValid() && lockObj.badge.isValid) { if (lockObj.isValid() && lockObj.badge.isValid) {
bool expected;
while (true) { while (true) {
std::lock_guard<std::mutex> lock(mutex); expected = false;
if (write && read == 0) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
read = 1; if (write && read == 0) {
write = false; read = 1;
lockObj.isLocked = false; write = false;
lockObj.badge.isValid = false; lockObj.isLocked = false;
return LockObj<false>(selfWeakPtr, Badge{}); lockObj.badge.isValid = false;
spinLock.store(false, std::memory_order_release);
return LockObj<false>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
} }
} else { } else {
@ -98,13 +142,18 @@ UDPC::LockObj<false> UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockO
UDPC::LockObj<false> UDPC::SharedSpinLock::try_trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) { UDPC::LockObj<false> UDPC::SharedSpinLock::try_trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) {
if (lockObj.isValid() && lockObj.badge.isValid) { if (lockObj.isValid() && lockObj.badge.isValid) {
std::lock_guard<std::mutex> lock(mutex); bool expected = false;
if (write && read == 0) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
read = 1; if (write && read == 0) {
write = false; read = 1;
lockObj.isLocked = false; write = false;
lockObj.badge.isValid = false; lockObj.isLocked = false;
return LockObj<false>(selfWeakPtr, Badge{}); lockObj.badge.isValid = false;
spinLock.store(false, std::memory_order_release);
return LockObj<false>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
} }
return LockObj<false>{}; return LockObj<false>{};
@ -112,14 +161,20 @@ UDPC::LockObj<false> UDPC::SharedSpinLock::try_trade_write_for_read_lock(UDPC::L
UDPC::LockObj<true> UDPC::SharedSpinLock::trade_read_for_write_lock(UDPC::LockObj<false> &lockObj) { UDPC::LockObj<true> UDPC::SharedSpinLock::trade_read_for_write_lock(UDPC::LockObj<false> &lockObj) {
if (lockObj.isValid() && lockObj.badge.isValid) { if (lockObj.isValid() && lockObj.badge.isValid) {
bool expected;
while (true) { while (true) {
std::lock_guard<std::mutex> lock(mutex); expected = false;
if (!write && read == 1) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
read = 0; if (!write && read == 1) {
write = true; read = 0;
lockObj.isLocked = false; write = true;
lockObj.badge.isValid = false; lockObj.isLocked = false;
return LockObj<true>(selfWeakPtr, Badge{}); lockObj.badge.isValid = false;
spinLock.store(false, std::memory_order_release);
return LockObj<true>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
} }
} else { } else {
@ -129,13 +184,18 @@ UDPC::LockObj<true> UDPC::SharedSpinLock::trade_read_for_write_lock(UDPC::LockOb
UDPC::LockObj<true> UDPC::SharedSpinLock::try_trade_read_for_write_lock(UDPC::LockObj<false> &lockObj) { UDPC::LockObj<true> UDPC::SharedSpinLock::try_trade_read_for_write_lock(UDPC::LockObj<false> &lockObj) {
if (lockObj.isValid() && lockObj.badge.isValid) { if (lockObj.isValid() && lockObj.badge.isValid) {
std::lock_guard<std::mutex> lock(mutex); bool expected = false;
if (!write && read == 1) { if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) {
read = 0; if (!write && read == 1) {
write = true; read = 0;
lockObj.isLocked = false; write = true;
lockObj.badge.isValid = false; lockObj.isLocked = false;
return LockObj<true>(selfWeakPtr, Badge{}); lockObj.badge.isValid = false;
spinLock.store(false, std::memory_order_release);
return LockObj<true>(selfWeakPtr, Badge{});
} else {
spinLock.store(false, std::memory_order_release);
}
} }
} }
return LockObj<true>{}; return LockObj<true>{};

View file

@ -2,7 +2,6 @@
#define UDPC_CXX11_SHARED_SPIN_LOCK_H_ #define UDPC_CXX11_SHARED_SPIN_LOCK_H_
#include <memory> #include <memory>
#include <mutex>
#include <atomic> #include <atomic>
namespace UDPC { namespace UDPC {
@ -75,9 +74,9 @@ public:
SharedSpinLock(const SharedSpinLock&) = delete; SharedSpinLock(const SharedSpinLock&) = delete;
SharedSpinLock& operator=(const SharedSpinLock&) = delete; SharedSpinLock& operator=(const SharedSpinLock&) = delete;
// Allow move. // Disallow move.
SharedSpinLock(SharedSpinLock&&) = default; SharedSpinLock(SharedSpinLock&&) = delete;
SharedSpinLock& operator=(SharedSpinLock&&) = default; SharedSpinLock& operator=(SharedSpinLock&&) = delete;
LockObj<false> spin_read_lock(); LockObj<false> spin_read_lock();
LockObj<false> try_spin_read_lock(); LockObj<false> try_spin_read_lock();
@ -97,7 +96,10 @@ private:
SharedSpinLock(); SharedSpinLock();
Weak selfWeakPtr; Weak selfWeakPtr;
std::mutex mutex;
/// Used to lock the read/write member variables.
volatile std::atomic_bool spinLock;
unsigned int read; unsigned int read;
bool write; bool write;