Refactor shared-spin-lock to use atomic "spinLock"
This commit is contained in:
parent
3212f3e7dc
commit
fe1eefdd7c
2 changed files with 119 additions and 57 deletions
|
@ -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>{};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue