Conscience Core
shared_recursive_mutex.h
Go to the documentation of this file.
1 //
2 // Created by Louis Grignon on 06/02/2025.
3 //
4 
5 #ifndef SHARED_RECURSIVE_MUTEX_H
6 #define SHARED_RECURSIVE_MUTEX_H
7 #include <shared_mutex>
8 
14  //the template parameter is needed to be able to define multiple instances of the shared_recursive_mutex
15  //since the implementation relies upon thread local storage we need a unique type per lock that is needed
16  //is doesn't matter what the input type is, along as it's unique (that's why it's called PhantomType)
17  template<typename PhantomType>
19  public:
29  {
31  return instance;
32  }
33 
44  void lock();
45 
55  void lock_shared();
56 
62  void unlock();
63 
68  void unlock_shared();
75  [[nodiscard]] bool try_lock();
79  [[nodiscard]] bool try_lock_shared();
83  [[nodiscard]] bool is_locked() const;
87  [[nodiscard]] bool is_locked_shared() const;
88 
89  private:
90  shared_recursive_mutex_t() = default;
91 
92  std::shared_mutex m_sharedMtx;
93  static inline thread_local uint32_t g_readers = 0;
94  static inline thread_local uint32_t g_writers = 0;
95  };
96 
97  template<typename PhantomType>
99  {
100  if (g_writers == 0 && g_readers == 0)
101  {
102  m_sharedMtx.lock();
103  }
104  else if (g_writers == 0 && g_readers > 0)
105  {
106  m_sharedMtx.unlock_shared();
107  m_sharedMtx.lock();
108  }
109  ++g_writers;
110  }
111  template<typename PhantomType>
113  {
114  //if we are locking shared
115  if (g_writers > 0)
116  {
117  ++g_writers;
118  }
119  else if (g_readers > 0)
120  {
121  ++g_readers;
122  }
123  else if (g_readers == 0)
124  {
125  m_sharedMtx.lock_shared();
126  ++g_readers;
127  }
128  }
129  template<typename PhantomType>
131  {
132  --g_writers;
133  if (g_writers > 0)
134  return;
135  if (g_writers == 0)
136  {
137  m_sharedMtx.unlock();
138  if (g_readers > 0)
139  m_sharedMtx.lock_shared();
140  }
141  }
142  template<typename PhantomType>
144  {
145  //if the g_writers are > 0 it means that when we got the read lock, this thread already has the write lock
146  if (g_writers > 0)
147  {
148  unlock();
149  return;
150  }
151  --g_readers;
152  if (g_readers == 0)
153  {
154  m_sharedMtx.unlock_shared();
155  }
156  }
157  template<typename PhantomType>
159  {
160  //we already have the lock, so we can simply increase the writer count
161  if (g_writers > 0)
162  {
163  ++g_writers;
164  return true;
165  }
166  //we already have a read lock, but we can't aquire the write lock without giving up the read lock
167  //so we have to return false here
168  if (g_readers > 0)
169  {
170  return false;
171  }
172  const bool aquiredLock = m_sharedMtx.try_lock();
173  if (aquiredLock)
174  {
175  ++g_writers;
176  }
177 
178  return aquiredLock;
179  }
180  template<typename PhantomType>
182  {
183  //we already have the lock, so we can simply increase the lock count
184  if (g_writers > 0 || g_readers > 0)
185  {
186  lock_shared();
187  return true;
188  }
189  const bool aquiredLock = m_sharedMtx.try_lock_shared();
190  if (aquiredLock)
191  {
192  ++g_readers;
193  }
194  return aquiredLock;
195  }
196  template<typename PhantomType>
198  {
199  return g_writers > 0;
200  }
201  template<typename PhantomType>
203  {
204  return g_readers > 0 && g_writers == 0;
205  }
206 
208 
209 }
210 
211 #endif //SHARED_RECURSIVE_MUTEX_H
conscience_utils::mutexutils::shared_recursive_mutex_t::instance
static shared_recursive_mutex_t & instance()
The shared_recursive_mutex_t is relying on thread local storage, so there can only be 1 valid instanc...
Definition: shared_recursive_mutex.h:28
conscience_utils::mutexutils::shared_recursive_mutex_t::is_locked
bool is_locked() const
Returns if this thread has write ownership.
Definition: shared_recursive_mutex.h:197
conscience_utils::mutexutils::shared_recursive_mutex_t::operator=
shared_recursive_mutex_t & operator=(const shared_recursive_mutex_t &)=delete
conscience_utils::mutexutils::shared_recursive_mutex_t::unlock_shared
void unlock_shared()
Unlocks the mutex for this thread if its level of ownership is 1. Otherwise reduces the level of owne...
Definition: shared_recursive_mutex.h:143
conscience_utils::mutexutils::shared_recursive_mutex_t::unlock
void unlock()
Unlocks the mutex for this thread if its level of write ownership is 1 and has no read ownership....
Definition: shared_recursive_mutex.h:130
conscience_utils::mutexutils
Definition: shared_recursive_mutex.h:9
conscience_utils::mutexutils::shared_recursive_mutex_t::try_lock
bool try_lock()
Tries to get write ownership if possible. If the thread has read (but no write) ownership this functi...
Definition: shared_recursive_mutex.h:158
conscience_utils::mutexutils::shared_recursive_mutex_t
Implementation of a fast shared_recursive_mutex Thanks to https://github.com/KonanM/shared_recursive_...
Definition: shared_recursive_mutex.h:18
conscience_utils::mutexutils::shared_recursive_mutex_t::lock_shared
void lock_shared()
Locks the mutex for sharable read access. Blocks execution as long as read access is not available:
Definition: shared_recursive_mutex.h:112
conscience_utils::mutexutils::shared_recursive_mutex_t::is_locked_shared
bool is_locked_shared() const
Returns true if this thread has only read ownership.
Definition: shared_recursive_mutex.h:202
conscience_utils::mutexutils::shared_recursive_mutex_t::try_lock_shared
bool try_lock_shared()
Tries to get read ownership if possible.
Definition: shared_recursive_mutex.h:181
conscience_utils::mutexutils::shared_recursive_mutex_t::lock
void lock()
Locks the mutex for exclusive write access for this thread. Blocks execution as long as write access ...
Definition: shared_recursive_mutex.h:98