]> git.seodisparate.com - UDPConnection/commitdiff
Refactor shared-spin-lock to use atomic "spinLock"
authorStephen Seo <seo.disparate@gmail.com>
Wed, 18 Oct 2023 13:28:40 +0000 (22:28 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 12 Jan 2024 04:32:05 +0000 (13:32 +0900)
src/CXX11_shared_spin_lock.cpp
src/CXX11_shared_spin_lock.hpp

index e9fb27cf4a3532ea091a8d9b7b4d553a26f12263..a3cea8ed79cb67835dad9eb75fbb26134b9d32ad 100644 (file)
@@ -18,77 +18,121 @@ UDPC::SharedSpinLock::Ptr UDPC::SharedSpinLock::newInstance() {
 
 UDPC::SharedSpinLock::SharedSpinLock() :
 selfWeakPtr(),
-mutex(),
+spinLock(false),
 read(0),
 write(false)
 {}
 
 UDPC::LockObj<false> UDPC::SharedSpinLock::spin_read_lock() {
+    bool expected;
     while (true) {
-        std::lock_guard<std::mutex> lock(mutex);
-        if (!write) {
-            ++read;
-            return LockObj<false>(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<false>(selfWeakPtr, Badge{});
+            } else {
+                spinLock.store(false, std::memory_order_release);
+            }
         }
     }
 }
 
 UDPC::LockObj<false> UDPC::SharedSpinLock::try_spin_read_lock() {
-    std::lock_guard<std::mutex> lock(mutex);
-    if (!write) {
-        ++read;
-        return LockObj<false>(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<false>(selfWeakPtr, Badge{});
+        } else {
+            spinLock.store(false, std::memory_order_release);
+        }
     }
     return LockObj<false>{};
 }
 
 void UDPC::SharedSpinLock::read_unlock(UDPC::Badge &&badge) {
     if (badge.isValid) {
-        std::lock_guard<std::mutex> 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<true> UDPC::SharedSpinLock::spin_write_lock() {
+    bool expected;
     while (true) {
-        std::lock_guard<std::mutex> lock(mutex);
-        if (!write && read == 0) {
-            write = true;
-            return LockObj<true>(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<true>(selfWeakPtr, Badge{});
+            } else {
+                spinLock.store(false, std::memory_order_release);
+            }
         }
     }
 }
 
 UDPC::LockObj<true> UDPC::SharedSpinLock::try_spin_write_lock() {
-    std::lock_guard<std::mutex> lock(mutex);
-    if (!write && read == 0) {
-        write = true;
-        return LockObj<true>(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<true>(selfWeakPtr, Badge{});
+        } else {
+            spinLock.store(false, std::memory_order_release);
+        }
     }
     return LockObj<true>{};
 }
 
 void UDPC::SharedSpinLock::write_unlock(UDPC::Badge &&badge) {
     if (badge.isValid) {
-        std::lock_guard<std::mutex> 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<false> UDPC::SharedSpinLock::trade_write_for_read_lock(UDPC::LockObj<true> &lockObj) {
     if (lockObj.isValid() && lockObj.badge.isValid) {
+        bool expected;
         while (true) {
-            std::lock_guard<std::mutex> lock(mutex);
-            if (write && read == 0) {
-                read = 1;
-                write = false;
-                lockObj.isLocked = false;
-                lockObj.badge.isValid = false;
-                return LockObj<false>(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<false>(selfWeakPtr, Badge{});
+                } else {
+                    spinLock.store(false, std::memory_order_release);
+                }
             }
         }
     } 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) {
     if (lockObj.isValid() && lockObj.badge.isValid) {
-        std::lock_guard<std::mutex> lock(mutex);
-        if (write && read == 0) {
-            read = 1;
-            write = false;
-            lockObj.isLocked = false;
-            lockObj.badge.isValid = false;
-            return LockObj<false>(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<false>(selfWeakPtr, Badge{});
+            } else {
+                spinLock.store(false, std::memory_order_release);
+            }
         }
     }
     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) {
     if (lockObj.isValid() && lockObj.badge.isValid) {
+        bool expected;
         while (true) {
-            std::lock_guard<std::mutex> lock(mutex);
-            if (!write && read == 1) {
-                read = 0;
-                write = true;
-                lockObj.isLocked = false;
-                lockObj.badge.isValid = false;
-                return LockObj<true>(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<true>(selfWeakPtr, Badge{});
+                } else {
+                    spinLock.store(false, std::memory_order_release);
+                }
             }
         }
     } 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) {
     if (lockObj.isValid() && lockObj.badge.isValid) {
-        std::lock_guard<std::mutex> lock(mutex);
-        if (!write && read == 1) {
-            read = 0;
-            write = true;
-            lockObj.isLocked = false;
-            lockObj.badge.isValid = false;
-            return LockObj<true>(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<true>(selfWeakPtr, Badge{});
+            } else {
+                spinLock.store(false, std::memory_order_release);
+            }
         }
     }
     return LockObj<true>{};
index 67c2f223978201aa5b4a032ac721f7a7e6a0f94a..53b51d1a3866ea794d26a1719787266efe84c8b8 100644 (file)
@@ -2,7 +2,6 @@
 #define UDPC_CXX11_SHARED_SPIN_LOCK_H_
 
 #include <memory>
-#include <mutex>
 #include <atomic>
 
 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<false> spin_read_lock();
     LockObj<false> 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;