From 59b566137b85f9a5554eecaaec7c15d192a4f6a8 Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Thu, 11 Jul 2024 16:43:35 +0200 Subject: [PATCH 01/11] [core] Add a shared mutex class --- srtcore/sync.h | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/srtcore/sync.h b/srtcore/sync.h index fb6d56432..5909b9a05 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -943,6 +943,81 @@ CUDTException& GetThreadLocalError(); /// @param[in] maxVal maximum allowed value of the resulting random number. int genRandomInt(int minVal, int maxVal); +class SharedMutex +{ + private: + Condition m_LockWriteCond; + Condition m_LockReadCond; + + Mutex m_Mutex; + int m_iCountRead; + bool m_bWriterLocked; + + + public: + SharedMutex() + :m_LockWriteCond() + ,m_LockReadCond() + ,m_Mutex() + ,m_iCountRead(0) + ,m_bWriterLocked(false) + { + m_iCountRead = 0; + m_bWriterLocked = false; + + setupCond(m_LockReadCond, "SharedMutex::m_pLockReadCond"); + setupCond(m_LockWriteCond, "SharedMutex::m_pLockWriteCond"); + setupMutex(m_Mutex, "SharedMutex::m_pMutex"); + + } + ~SharedMutex() + { + releaseMutex(m_Mutex); + releaseCond(m_LockWriteCond); + releaseCond(m_LockReadCond); + } + + void lockWrite() + { + UniqueLock l1(m_Mutex); + if(m_bWriterLocked) + m_LockWriteCond.wait(l1); + m_bWriterLocked = true; + if(m_iCountRead) + m_LockReadCond.wait(l1); + + + } + + void unlockWrite() + { + UniqueLock l2(m_Mutex); + m_bWriterLocked = false; + l2.unlock(); + m_LockWriteCond.notify_all(); + + } + + void lockRead() + { + UniqueLock l3(m_Mutex); + if(m_bWriterLocked) + m_LockWriteCond.wait(l3); + m_iCountRead++; + } + + void unlockRead() + { + ScopedLock l4(m_Mutex); + m_iCountRead--; + if(m_bWriterLocked && m_iCountRead == 0) + m_LockReadCond.notify_one(); + else if (m_iCountRead > 0) + m_LockWriteCond.notify_one(); + } + +}; + } // namespace sync } // namespace srt From 4d55fa55634ebc047845a8d18672dbc30c9e0b0f Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Mon, 15 Jul 2024 15:01:10 +0200 Subject: [PATCH 02/11] [core] Improved syntax of SharedMutex class Improved syntax Changed lock/unlock functions name to match reference implementation Add unit tests for SharedMutex --- srtcore/sync.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++++ srtcore/sync.h | 77 +++++++++------------------------ test/test_sync.cpp | 85 ++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 58 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index a7cebb909..299a18661 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -172,6 +172,8 @@ namespace sync { srt::sync::CEvent g_Sync; + + } // namespace sync } // namespace srt @@ -357,3 +359,105 @@ int srt::sync::genRandomInt(int minVal, int maxVal) #endif // HAVE_CXX11 } + +//////////////////////////////////////////////////////////////////////////////// +// +// Shared Mutex +// +//////////////////////////////////////////////////////////////////////////////// + +srt::sync::SharedMutex::SharedMutex() + :m_LockWriteCond() + ,m_LockReadCond() + ,m_Mutex() + ,m_iCountRead(0) + ,m_bWriterLocked(false) +{ + m_iCountRead = 0; + m_bWriterLocked = false; + + setupCond(m_LockReadCond, "SharedMutex::m_pLockReadCond"); + setupCond(m_LockWriteCond, "SharedMutex::m_pLockWriteCond"); + setupMutex(m_Mutex, "SharedMutex::m_pMutex"); +} + +srt::sync::SharedMutex::~SharedMutex() +{ + releaseMutex(m_Mutex); + releaseCond(m_LockWriteCond); + releaseCond(m_LockReadCond); +} + +void srt::sync::SharedMutex::lock() +{ + UniqueLock l1(m_Mutex); + if (m_bWriterLocked) + m_LockWriteCond.wait(l1); + + m_bWriterLocked = true; + + if (m_iCountRead) + m_LockReadCond.wait(l1); +} + +bool srt::sync::SharedMutex::try_lock() +{ + UniqueLock l1(m_Mutex); + if (m_bWriterLocked || m_iCountRead > 0) + return false; + else + { + m_bWriterLocked = true; + return true; + } +} + +void srt::sync::SharedMutex::unlock() +{ + UniqueLock lk(m_Mutex); + m_bWriterLocked = false; + + lk.unlock(); + m_LockWriteCond.notify_all(); +} + +void srt::sync::SharedMutex::lock_shared() +{ + UniqueLock lk(m_Mutex); + if (m_bWriterLocked) + m_LockWriteCond.wait(lk); + + m_iCountRead++; +} + +bool srt::sync::SharedMutex::try_lock_shared() +{ + UniqueLock lk(m_Mutex); + if (m_bWriterLocked) + return false; + else + { + m_iCountRead++; + return true; + } +} + +void srt::sync::SharedMutex::unlock_shared() +{ + ScopedLock lk(m_Mutex); + + m_iCountRead--; + if (m_iCountRead < 0) + m_iCountRead = 0; + + if (m_bWriterLocked && m_iCountRead == 0) + m_LockReadCond.notify_one(); + else if (m_iCountRead > 0) + m_LockWriteCond.notify_one(); + +} + +int srt::sync::SharedMutex::getReaderCount() +{ + return m_iCountRead; +} \ No newline at end of file diff --git a/srtcore/sync.h b/srtcore/sync.h index 5909b9a05..22920bd21 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -943,78 +943,39 @@ CUDTException& GetThreadLocalError(); /// @param[in] maxVal maximum allowed value of the resulting random number. int genRandomInt(int minVal, int maxVal); + +// Implementation of a read-write mutex. +// This allows multiple readers at a time, or a single writer class SharedMutex { + public: + SharedMutex(); + ~SharedMutex(); + private: Condition m_LockWriteCond; Condition m_LockReadCond; Mutex m_Mutex; + int m_iCountRead; bool m_bWriterLocked; - + // Acquire the lock for writting purposes. Only one thread can acquire this lock at a time + // Once it is locked, no reader can acquire it public: - SharedMutex() - :m_LockWriteCond() - ,m_LockReadCond() - ,m_Mutex() - ,m_iCountRead(0) - ,m_bWriterLocked(false) - { - m_iCountRead = 0; - m_bWriterLocked = false; + void lock() SRT_ATTR_ACQUIRE(); + bool try_lock() SRT_ATTR_TRY_ACQUIRE(); + void unlock() SRT_ATTR_RELEASE(); - setupCond(m_LockReadCond, "SharedMutex::m_pLockReadCond"); - setupCond(m_LockWriteCond, "SharedMutex::m_pLockWriteCond"); - setupMutex(m_Mutex, "SharedMutex::m_pMutex"); - - } - ~SharedMutex() - { - releaseMutex(m_Mutex); - releaseCond(m_LockWriteCond); - releaseCond(m_LockReadCond); - } - - void lockWrite() - { - UniqueLock l1(m_Mutex); - if(m_bWriterLocked) - m_LockWriteCond.wait(l1); - m_bWriterLocked = true; - if(m_iCountRead) - m_LockReadCond.wait(l1); + // Acquire the lock if no writter already has it. For read purpose only + // Several readers can lock this at the same time. + void lock_shared() SRT_ATTR_ACQUIRE_SHARED(); + bool try_lock_shared() SRT_ATTR_TRY_ACQUIRE_SHARED(); + void unlock_shared() SRT_ATTR_RELEASE_SHARED(); + int getReaderCount(); - } - - void unlockWrite() - { - UniqueLock l2(m_Mutex); - m_bWriterLocked = false; - l2.unlock(); - m_LockWriteCond.notify_all(); - - } - - void lockRead() - { - UniqueLock l3(m_Mutex); - if(m_bWriterLocked) - m_LockWriteCond.wait(l3); - m_iCountRead++; - } - - void unlockRead() - { - ScopedLock l4(m_Mutex); - m_iCountRead--; - if(m_bWriterLocked && m_iCountRead == 0) - m_LockReadCond.notify_one(); - else if (m_iCountRead > 0) - m_LockWriteCond.notify_one(); - } }; diff --git a/test/test_sync.cpp b/test/test_sync.cpp index e0454a581..9e2064cc1 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -609,6 +609,91 @@ TEST(SyncThread, Joinable) EXPECT_FALSE(foo.joinable()); } +/*****************************************************************************/ +/* + * SharedMutex + */ + /*****************************************************************************/ +TEST(SharedMutex, LockWriteRead) +{ + SharedMutex mut; + + mut.lock(); + EXPECT_FALSE(mut.try_lock_shared()); + +} + +TEST(SharedMutex, LockReadWrite) +{ + SharedMutex mut; + + mut.lock_shared(); + EXPECT_FALSE(mut.try_lock()); + +} + +TEST(SharedMutex, LockReadTwice) +{ + SharedMutex mut; + + mut.lock_shared(); + mut.lock_shared(); + EXPECT_TRUE(mut.try_lock_shared()); +} + +TEST(SharedMutex, LockWriteTwice) +{ + SharedMutex mut; + + mut.lock(); + EXPECT_FALSE(mut.try_lock()); +} + +TEST(SharedMutex, LockUnlockWrite) +{ + SharedMutex mut; + mut.lock(); + EXPECT_FALSE(mut.try_lock()); + mut.unlock(); + EXPECT_TRUE(mut.try_lock()); +} + +TEST(SharedMutex, LockUnlockRead) +{ + SharedMutex mut; + + mut.lock_shared(); + EXPECT_FALSE(mut.try_lock()); + + mut.unlock_shared(); + EXPECT_TRUE(mut.try_lock()); +} + +TEST(SharedMutex, LockedReadCount) +{ + SharedMutex mut; + int count = 0; + + mut.lock_shared(); + count++; + ASSERT_EQ(mut.getReaderCount(), count); + + mut.lock_shared(); + count++; + ASSERT_EQ(mut.getReaderCount(), count); + + mut.unlock_shared(); + count--; + ASSERT_EQ(mut.getReaderCount(), count); + + mut.unlock_shared(); + count--; + ASSERT_EQ(mut.getReaderCount(), count); + + EXPECT_TRUE(mut.try_lock()); +} + + /*****************************************************************************/ /* * FormatTime From 7dc9d620a3af60213b2c2bd9d5bc68cd3df8e2ef Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Mon, 15 Jul 2024 15:11:39 +0200 Subject: [PATCH 03/11] [core] Removed SRT_ATTR_XXX from SharedLock --- srtcore/sync.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/srtcore/sync.h b/srtcore/sync.h index 22920bd21..a92f27374 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -964,15 +964,15 @@ class SharedMutex // Acquire the lock for writting purposes. Only one thread can acquire this lock at a time // Once it is locked, no reader can acquire it public: - void lock() SRT_ATTR_ACQUIRE(); - bool try_lock() SRT_ATTR_TRY_ACQUIRE(); - void unlock() SRT_ATTR_RELEASE(); + void lock(); + bool try_lock(); + void unlock(); // Acquire the lock if no writter already has it. For read purpose only // Several readers can lock this at the same time. - void lock_shared() SRT_ATTR_ACQUIRE_SHARED(); - bool try_lock_shared() SRT_ATTR_TRY_ACQUIRE_SHARED(); - void unlock_shared() SRT_ATTR_RELEASE_SHARED(); + void lock_shared(); + bool try_lock_shared(); + void unlock_shared(); int getReaderCount(); From deeb9c913dfcab67469549c6011eab9bc90e212a Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Mon, 29 Jul 2024 13:49:35 +0200 Subject: [PATCH 04/11] [core] Fix syntax --- srtcore/sync.cpp | 37 ++++++++++++++++--------------------- srtcore/sync.h | 8 ++++---- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index 299a18661..7a68c2a35 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -172,8 +172,6 @@ namespace sync { srt::sync::CEvent g_Sync; - - } // namespace sync } // namespace srt @@ -367,15 +365,12 @@ int srt::sync::genRandomInt(int minVal, int maxVal) //////////////////////////////////////////////////////////////////////////////// srt::sync::SharedMutex::SharedMutex() - :m_LockWriteCond() - ,m_LockReadCond() - ,m_Mutex() - ,m_iCountRead(0) - ,m_bWriterLocked(false) + : m_LockWriteCond() + , m_LockReadCond() + , m_Mutex() + , m_iCountRead(0) + , m_bWriterLocked(false) { - m_iCountRead = 0; - m_bWriterLocked = false; - setupCond(m_LockReadCond, "SharedMutex::m_pLockReadCond"); setupCond(m_LockWriteCond, "SharedMutex::m_pLockWriteCond"); setupMutex(m_Mutex, "SharedMutex::m_pMutex"); @@ -405,11 +400,10 @@ bool srt::sync::SharedMutex::try_lock() UniqueLock l1(m_Mutex); if (m_bWriterLocked || m_iCountRead > 0) return false; - else - { - m_bWriterLocked = true; - return true; - } + + m_bWriterLocked = true; + return true; + } void srt::sync::SharedMutex::unlock() @@ -417,8 +411,8 @@ void srt::sync::SharedMutex::unlock() UniqueLock lk(m_Mutex); m_bWriterLocked = false; - lk.unlock(); m_LockWriteCond.notify_all(); + lk.unlock(); } void srt::sync::SharedMutex::lock_shared() @@ -435,11 +429,9 @@ bool srt::sync::SharedMutex::try_lock_shared() UniqueLock lk(m_Mutex); if (m_bWriterLocked) return false; - else - { - m_iCountRead++; - return true; - } + + m_iCountRead++; + return true; } void srt::sync::SharedMutex::unlock_shared() @@ -447,6 +439,8 @@ void srt::sync::SharedMutex::unlock_shared() ScopedLock lk(m_Mutex); m_iCountRead--; + + SRT_ASSERT(m_iCountRead >= 0); if (m_iCountRead < 0) m_iCountRead = 0; @@ -459,5 +453,6 @@ void srt::sync::SharedMutex::unlock_shared() int srt::sync::SharedMutex::getReaderCount() { + ScopedLock lk(m_Mutex); return m_iCountRead; } \ No newline at end of file diff --git a/srtcore/sync.h b/srtcore/sync.h index a92f27374..39074f51e 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -944,11 +944,11 @@ CUDTException& GetThreadLocalError(); int genRandomInt(int minVal, int maxVal); -// Implementation of a read-write mutex. -// This allows multiple readers at a time, or a single writer +/// Implementation of a read-write mutex. +/// This allows multiple readers at a time, or a single writer class SharedMutex { - public: +public: SharedMutex(); ~SharedMutex(); @@ -963,7 +963,7 @@ class SharedMutex // Acquire the lock for writting purposes. Only one thread can acquire this lock at a time // Once it is locked, no reader can acquire it - public: +public: void lock(); bool try_lock(); void unlock(); From 58d575f316a55357d15f5c91d3fd359f7e288689 Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Tue, 30 Jul 2024 08:51:37 +0200 Subject: [PATCH 05/11] [core] Handle spurious wake up in shared mutex locking functions --- srtcore/sync.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index 7a68c2a35..73cad7667 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -386,12 +386,12 @@ srt::sync::SharedMutex::~SharedMutex() void srt::sync::SharedMutex::lock() { UniqueLock l1(m_Mutex); - if (m_bWriterLocked) + while (m_bWriterLocked) m_LockWriteCond.wait(l1); m_bWriterLocked = true; - if (m_iCountRead) + while (m_iCountRead) m_LockReadCond.wait(l1); } @@ -418,7 +418,7 @@ void srt::sync::SharedMutex::unlock() void srt::sync::SharedMutex::lock_shared() { UniqueLock lk(m_Mutex); - if (m_bWriterLocked) + while (m_bWriterLocked) m_LockWriteCond.wait(lk); m_iCountRead++; From d7a24bc34965029b58ef5b3b33349b26daf3ba33 Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Tue, 30 Jul 2024 09:54:17 +0200 Subject: [PATCH 06/11] [core] More syntax adjustements --- srtcore/sync.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/srtcore/sync.h b/srtcore/sync.h index 39074f51e..61dcece9a 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -952,7 +952,7 @@ class SharedMutex SharedMutex(); ~SharedMutex(); - private: +private: Condition m_LockWriteCond; Condition m_LockReadCond; @@ -961,20 +961,20 @@ class SharedMutex int m_iCountRead; bool m_bWriterLocked; - // Acquire the lock for writting purposes. Only one thread can acquire this lock at a time - // Once it is locked, no reader can acquire it + /// Acquire the lock for writting purposes. Only one thread can acquire this lock at a time + /// Once it is locked, no reader can acquire it public: void lock(); bool try_lock(); void unlock(); - // Acquire the lock if no writter already has it. For read purpose only - // Several readers can lock this at the same time. + /// Acquire the lock if no writter already has it. For read purpose only + /// Several readers can lock this at the same time. void lock_shared(); bool try_lock_shared(); void unlock_shared(); - int getReaderCount(); + int getReaderCount() const; }; From 89f76fe7e18ba50791d8d2d8db33da1fe147e84c Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Wed, 31 Jul 2024 08:21:18 +0200 Subject: [PATCH 07/11] [core] Removed mutex from getReaderCount, add const attribute --- srtcore/sync.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index 73cad7667..e5ecbf5aa 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -451,8 +451,7 @@ void srt::sync::SharedMutex::unlock_shared() } -int srt::sync::SharedMutex::getReaderCount() +int srt::sync::SharedMutex::getReaderCount() const { - ScopedLock lk(m_Mutex); return m_iCountRead; } \ No newline at end of file From edf9aa5917666815ba4c08cedf7a565627e2d6b3 Mon Sep 17 00:00:00 2001 From: yomnes0 Date: Wed, 31 Jul 2024 09:49:26 +0200 Subject: [PATCH 08/11] [core] Add a mutable qualifier to m_Mutex from SharedMutex Add a lock to getReaderCount --- srtcore/sync.cpp | 1 + srtcore/sync.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index e5ecbf5aa..eff84feda 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -453,5 +453,6 @@ void srt::sync::SharedMutex::unlock_shared() int srt::sync::SharedMutex::getReaderCount() const { + ScopedLock lk(m_Mutex); return m_iCountRead; } \ No newline at end of file diff --git a/srtcore/sync.h b/srtcore/sync.h index 61dcece9a..c8ee88cce 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -956,7 +956,7 @@ class SharedMutex Condition m_LockWriteCond; Condition m_LockReadCond; - Mutex m_Mutex; + mutable Mutex m_Mutex; int m_iCountRead; bool m_bWriterLocked; From 06e15cfb2ad444640aef0c974ca1d6cabeede5c3 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 1 Aug 2024 11:39:10 +0200 Subject: [PATCH 09/11] Apply suggestions from code review --- srtcore/sync.cpp | 4 +--- srtcore/sync.h | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index eff84feda..aefed2239 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -403,16 +403,14 @@ bool srt::sync::SharedMutex::try_lock() m_bWriterLocked = true; return true; - } void srt::sync::SharedMutex::unlock() { - UniqueLock lk(m_Mutex); + ScopedLock lk(m_Mutex); m_bWriterLocked = false; m_LockWriteCond.notify_all(); - lk.unlock(); } void srt::sync::SharedMutex::lock_shared() diff --git a/srtcore/sync.h b/srtcore/sync.h index c8ee88cce..220912e4a 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -975,8 +975,6 @@ class SharedMutex void unlock_shared(); int getReaderCount() const; - - }; } // namespace sync From 6497a503872766b94eef50b4cdcb4655783499e1 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 1 Aug 2024 12:00:30 +0200 Subject: [PATCH 10/11] Removed unnecessary condition signaling. --- srtcore/sync.cpp | 2 -- srtcore/sync.h | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index aefed2239..bfe153657 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -444,8 +444,6 @@ void srt::sync::SharedMutex::unlock_shared() if (m_bWriterLocked && m_iCountRead == 0) m_LockReadCond.notify_one(); - else if (m_iCountRead > 0) - m_LockWriteCond.notify_one(); } diff --git a/srtcore/sync.h b/srtcore/sync.h index 220912e4a..52778084f 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -945,7 +945,10 @@ int genRandomInt(int minVal, int maxVal); /// Implementation of a read-write mutex. -/// This allows multiple readers at a time, or a single writer +/// This allows multiple readers at a time, or a single writer. +/// TODO: The class can be improved if needed to give writer a preference +/// by adding additional m_bWriterWaiting member variable. +/// TODO: The m_iCountRead could be made atomic to make unlok_shared() faster and lock-free. class SharedMutex { public: From d69f848d005723fffbd585df9c49e82f35e54d1a Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 1 Aug 2024 12:02:13 +0200 Subject: [PATCH 11/11] Improved the TODO comment. --- srtcore/sync.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srtcore/sync.h b/srtcore/sync.h index 52778084f..8fee25831 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -947,7 +947,7 @@ int genRandomInt(int minVal, int maxVal); /// Implementation of a read-write mutex. /// This allows multiple readers at a time, or a single writer. /// TODO: The class can be improved if needed to give writer a preference -/// by adding additional m_bWriterWaiting member variable. +/// by adding additional m_iWritersWaiting member variable (counter). /// TODO: The m_iCountRead could be made atomic to make unlok_shared() faster and lock-free. class SharedMutex {