From fe1eefdd7c69dee4c68211dda584a89e8594d5f1 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Wed, 18 Oct 2023 22:28:40 +0900 Subject: [PATCH] Refactor shared-spin-lock to use atomic "spinLock" --- src/CXX11_shared_spin_lock.cpp | 164 ++++++++++++++++++++++----------- src/CXX11_shared_spin_lock.hpp | 12 ++- 2 files changed, 119 insertions(+), 57 deletions(-) diff --git a/src/CXX11_shared_spin_lock.cpp b/src/CXX11_shared_spin_lock.cpp index e9fb27c..a3cea8e 100644 --- a/src/CXX11_shared_spin_lock.cpp +++ b/src/CXX11_shared_spin_lock.cpp @@ -18,77 +18,121 @@ UDPC::SharedSpinLock::Ptr UDPC::SharedSpinLock::newInstance() { UDPC::SharedSpinLock::SharedSpinLock() : selfWeakPtr(), -mutex(), +spinLock(false), read(0), write(false) {} UDPC::LockObj UDPC::SharedSpinLock::spin_read_lock() { + bool expected; while (true) { - std::lock_guard lock(mutex); - if (!write) { - ++read; - return LockObj(selfWeakPtr, Badge{}); + expected = false; + if(spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (!write) { + ++read; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } } } UDPC::LockObj UDPC::SharedSpinLock::try_spin_read_lock() { - std::lock_guard lock(mutex); - if (!write) { - ++read; - return LockObj(selfWeakPtr, Badge{}); + bool expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (!write) { + ++read; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } return LockObj{}; } void UDPC::SharedSpinLock::read_unlock(UDPC::Badge &&badge) { if (badge.isValid) { - std::lock_guard lock(mutex); - if (read > 0) { - --read; - badge.isValid = false; + bool expected; + while (true) { + expected = 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 UDPC::SharedSpinLock::spin_write_lock() { + bool expected; while (true) { - std::lock_guard lock(mutex); - if (!write && read == 0) { - write = true; - return LockObj(selfWeakPtr, Badge{}); + expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (!write && read == 0) { + write = true; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } } } UDPC::LockObj UDPC::SharedSpinLock::try_spin_write_lock() { - std::lock_guard lock(mutex); - if (!write && read == 0) { - write = true; - return LockObj(selfWeakPtr, Badge{}); + bool expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (!write && read == 0) { + write = true; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } return LockObj{}; } void UDPC::SharedSpinLock::write_unlock(UDPC::Badge &&badge) { if (badge.isValid) { - std::lock_guard lock(mutex); - write = false; - badge.isValid = false; + bool expected; + while(true) { + 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 UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockObj &lockObj) { if (lockObj.isValid() && lockObj.badge.isValid) { + bool expected; while (true) { - std::lock_guard lock(mutex); - if (write && read == 0) { - read = 1; - write = false; - lockObj.isLocked = false; - lockObj.badge.isValid = false; - return LockObj(selfWeakPtr, Badge{}); + expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (write && read == 0) { + read = 1; + write = false; + lockObj.isLocked = false; + lockObj.badge.isValid = false; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } } } else { @@ -98,13 +142,18 @@ UDPC::LockObj UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockO UDPC::LockObj UDPC::SharedSpinLock::try_trade_write_for_read_lock(UDPC::LockObj &lockObj) { if (lockObj.isValid() && lockObj.badge.isValid) { - std::lock_guard lock(mutex); - if (write && read == 0) { - read = 1; - write = false; - lockObj.isLocked = false; - lockObj.badge.isValid = false; - return LockObj(selfWeakPtr, Badge{}); + bool expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (write && read == 0) { + read = 1; + write = false; + lockObj.isLocked = false; + lockObj.badge.isValid = false; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } } return LockObj{}; @@ -112,14 +161,20 @@ UDPC::LockObj UDPC::SharedSpinLock::try_trade_write_for_read_lock(UDPC::L UDPC::LockObj UDPC::SharedSpinLock::trade_read_for_write_lock(UDPC::LockObj &lockObj) { if (lockObj.isValid() && lockObj.badge.isValid) { + bool expected; while (true) { - std::lock_guard lock(mutex); - if (!write && read == 1) { - read = 0; - write = true; - lockObj.isLocked = false; - lockObj.badge.isValid = false; - return LockObj(selfWeakPtr, Badge{}); + expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (!write && read == 1) { + read = 0; + write = true; + lockObj.isLocked = false; + lockObj.badge.isValid = false; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } } } else { @@ -129,13 +184,18 @@ UDPC::LockObj UDPC::SharedSpinLock::trade_read_for_write_lock(UDPC::LockOb UDPC::LockObj UDPC::SharedSpinLock::try_trade_read_for_write_lock(UDPC::LockObj &lockObj) { if (lockObj.isValid() && lockObj.badge.isValid) { - std::lock_guard lock(mutex); - if (!write && read == 1) { - read = 0; - write = true; - lockObj.isLocked = false; - lockObj.badge.isValid = false; - return LockObj(selfWeakPtr, Badge{}); + bool expected = false; + if (spinLock.compare_exchange_weak(expected, true, std::memory_order_acquire, std::memory_order_relaxed)) { + if (!write && read == 1) { + read = 0; + write = true; + lockObj.isLocked = false; + lockObj.badge.isValid = false; + spinLock.store(false, std::memory_order_release); + return LockObj(selfWeakPtr, Badge{}); + } else { + spinLock.store(false, std::memory_order_release); + } } } return LockObj{}; diff --git a/src/CXX11_shared_spin_lock.hpp b/src/CXX11_shared_spin_lock.hpp index 67c2f22..53b51d1 100644 --- a/src/CXX11_shared_spin_lock.hpp +++ b/src/CXX11_shared_spin_lock.hpp @@ -2,7 +2,6 @@ #define UDPC_CXX11_SHARED_SPIN_LOCK_H_ #include -#include #include namespace UDPC { @@ -75,9 +74,9 @@ public: SharedSpinLock(const SharedSpinLock&) = delete; SharedSpinLock& operator=(const SharedSpinLock&) = delete; - // Allow move. - SharedSpinLock(SharedSpinLock&&) = default; - SharedSpinLock& operator=(SharedSpinLock&&) = default; + // Disallow move. + SharedSpinLock(SharedSpinLock&&) = delete; + SharedSpinLock& operator=(SharedSpinLock&&) = delete; LockObj spin_read_lock(); LockObj try_spin_read_lock(); @@ -97,7 +96,10 @@ private: SharedSpinLock(); Weak selfWeakPtr; - std::mutex mutex; + + /// Used to lock the read/write member variables. + volatile std::atomic_bool spinLock; + unsigned int read; bool write;