Fast RTPS  Version 2.8.0
Fast RTPS
shared_mutex.hpp
1 // Copyright Howard Hinnant 2007-2010. Distributed under the Boost
2 // Software License, Version 1.0. (see http://www.boost.org/LICENSE_1_0.txt)
3 
8 #ifndef _UTILS_SHARED_MUTEX_HPP_
9 #define _UTILS_SHARED_MUTEX_HPP_
10 
11 #ifndef USE_THIRDPARTY_SHARED_MUTEX
12 # if defined(_MSC_VER) && _MSVC_LANG < 202302L
13 # pragma message("warning: USE_THIRDPARTY_SHARED_MUTEX not defined. By default use framework version.")
14 # else
15 # warning "USE_THIRDPARTY_SHARED_MUTEX not defined. By default use framework version."
16 # endif // if defined(_MSC_VER) && _MSVC_LANG < 202302L
17 # define USE_THIRDPARTY_SHARED_MUTEX 0
18 #endif // ifndef USE_THIRDPARTY_SHARED_MUTEX
19 
20 #if defined(__has_include) && __has_include(<version>)
21 # include <version>
22 #endif // if defined(__has_include) && __has_include(<version>)
23 
24 // Detect if the share_mutex feature is available
25 #if defined(__has_include) && __has_include(<version>) && !defined(__cpp_lib_shared_mutex) || \
26  /* allow users to ignore shared_mutex framework implementation */ \
27  (~USE_THIRDPARTY_SHARED_MUTEX + 1) || \
28  /* deprecated procedure if the good one is not available*/ \
29  ( !(defined(__has_include) && __has_include(<version>)) && \
30  !(defined(HAVE_CXX17) && HAVE_CXX17) && __cplusplus < 201703 )
31 
32 #include <mutex>
33 #include <condition_variable>
34 #include <climits>
35 #include <system_error>
36 
37 namespace eprosima {
38 
40 {
41  typedef std::mutex mutex_t;
42  typedef std::condition_variable cond_t;
43  typedef unsigned count_t;
44 
45  mutex_t mut_;
46  cond_t gate1_;
47  cond_t gate2_;
48  count_t state_;
49 
50  static const count_t write_entered_ = 1U << (sizeof(count_t) * CHAR_BIT - 1);
51  static const count_t n_readers_ = ~write_entered_;
52 
53 public:
54 
56  : state_(0)
57  {
58  }
59 
61  {
62  std::lock_guard<mutex_t> _(mut_);
63  }
64 
66  const shared_mutex&) = delete;
68  const shared_mutex&) = delete;
69 
70  // Exclusive ownership
71 
72  void lock()
73  {
74  std::unique_lock<mutex_t> lk(mut_);
75  while (state_ & write_entered_)
76  {
77  gate1_.wait(lk);
78  }
79  state_ |= write_entered_;
80  while (state_ & n_readers_)
81  {
82  gate2_.wait(lk);
83  }
84  }
85 
86  bool try_lock()
87  {
88  std::unique_lock<mutex_t> lk(mut_);
89  if (state_ == 0)
90  {
91  state_ = write_entered_;
92  return true;
93  }
94  return false;
95  }
96 
97  void unlock()
98  {
99  std::lock_guard<mutex_t> _(mut_);
100  state_ = 0;
101  gate1_.notify_all();
102  }
103 
104  // Shared ownership
105 
106  void lock_shared()
107  {
108  std::unique_lock<mutex_t> lk(mut_);
109  while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
110  {
111  gate1_.wait(lk);
112  }
113  count_t num_readers = (state_ & n_readers_) + 1;
114  state_ &= ~n_readers_;
115  state_ |= num_readers;
116  }
117 
119  {
120  std::unique_lock<mutex_t> lk(mut_);
121  count_t num_readers = state_ & n_readers_;
122  if (!(state_ & write_entered_) && num_readers != n_readers_)
123  {
124  ++num_readers;
125  state_ &= ~n_readers_;
126  state_ |= num_readers;
127  return true;
128  }
129  return false;
130  }
131 
133  {
134  std::lock_guard<mutex_t> _(mut_);
135  count_t num_readers = (state_ & n_readers_) - 1;
136  state_ &= ~n_readers_;
137  state_ |= num_readers;
138  if (state_ & write_entered_)
139  {
140  if (num_readers == 0)
141  {
142  gate2_.notify_one();
143  }
144  }
145  else
146  {
147  if (num_readers == n_readers_ - 1)
148  {
149  gate1_.notify_one();
150  }
151  }
152  }
153 
154 };
155 
156 template <class Mutex>
158 {
159 public:
160 
161  typedef Mutex mutex_type;
162 
163 private:
164 
165  mutex_type* m_;
166  bool owns_;
167 
168  struct __nat
169  {
170  int _;
171  };
172 
173 public:
174 
176  : m_(nullptr)
177  , owns_(false)
178  {
179  }
180 
181  explicit shared_lock(
182  mutex_type& m)
183  : m_(&m)
184  , owns_(true)
185  {
186  m_->lock_shared();
187  }
188 
190  mutex_type& m,
191  std::defer_lock_t)
192  : m_(&m)
193  , owns_(false)
194  {
195  }
196 
198  mutex_type& m,
199  std::try_to_lock_t)
200  : m_(&m)
201  , owns_(m.try_lock_shared())
202  {
203  }
204 
206  mutex_type& m,
207  std::adopt_lock_t)
208  : m_(&m)
209  , owns_(true)
210  {
211  }
212 
213  template <class Clock, class Duration>
215  mutex_type& m,
216  const std::chrono::time_point<Clock, Duration>& abs_time)
217  : m_(&m)
218  , owns_(m.try_lock_shared_until(abs_time))
219  {
220  }
221 
222  template <class Rep, class Period>
224  mutex_type& m,
225  const std::chrono::duration<Rep, Period>& rel_time)
226  : m_(&m)
227  , owns_(m.try_lock_shared_for(rel_time))
228  {
229  }
230 
232  {
233  if (owns_)
234  {
235  m_->unlock_shared();
236  }
237  }
238 
240  shared_lock const&) = delete;
242  shared_lock const&) = delete;
243 
245  shared_lock&& sl)
246  : m_(sl.m_)
247  , owns_(sl.owns_)
248  {
249  sl.m_ = nullptr; sl.owns_ = false;
250  }
251 
253  shared_lock&& sl)
254  {
255  if (owns_)
256  {
257  m_->unlock_shared();
258  }
259  m_ = sl.m_;
260  owns_ = sl.owns_;
261  sl.m_ = nullptr;
262  sl.owns_ = false;
263  return *this;
264  }
265 
266  explicit shared_lock(
267  std::unique_lock<mutex_type>&& ul)
268  : m_(ul.mutex())
269  , owns_(ul.owns_lock())
270  {
271  if (owns_)
272  {
273  m_->unlock_and_lock_shared();
274  }
275  ul.release();
276  }
277 
278  void lock();
279  bool try_lock();
280  template <class Rep, class Period>
282  const std::chrono::duration<Rep, Period>& rel_time)
283  {
284  return try_lock_until(std::chrono::steady_clock::now() + rel_time);
285  }
286 
287  template <class Clock, class Duration>
288  bool
290  const std::chrono::time_point<Clock, Duration>& abs_time);
291  void unlock();
292 
293  void swap(
294  shared_lock&& u)
295  {
296  std::swap(m_, u.m_);
297  std::swap(owns_, u.owns_);
298  }
299 
301  {
302  mutex_type* r = m_;
303  m_ = nullptr;
304  owns_ = false;
305  return r;
306  }
307 
308  bool owns_lock() const
309  {
310  return owns_;
311  }
312 
313  operator int __nat::* () const {
314  return owns_ ? &__nat::_ : 0;
315  }
316  mutex_type* mutex() const
317  {
318  return m_;
319  }
320 
321 };
322 
323 template <class Mutex>
324 void
326 {
327  if (m_ == nullptr)
328  {
329  throw std::system_error(std::error_code(EPERM, std::system_category()),
330  "shared_lock::lock: references null mutex");
331  }
332  if (owns_)
333  {
334  throw std::system_error(std::error_code(EDEADLK, std::system_category()),
335  "shared_lock::lock: already locked");
336  }
337  m_->lock_shared();
338  owns_ = true;
339 }
340 
341 template <class Mutex>
342 bool
344 {
345  if (m_ == nullptr)
346  {
347  throw std::system_error(std::error_code(EPERM, std::system_category()),
348  "shared_lock::try_lock: references null mutex");
349  }
350  if (owns_)
351  {
352  throw std::system_error(std::error_code(EDEADLK, std::system_category()),
353  "shared_lock::try_lock: already locked");
354  }
355  owns_ = m_->try_lock_shared();
356  return owns_;
357 }
358 
359 } //namespace eprosima
360 
361 #else // fallback to STL
362 
363 #include <shared_mutex>
364 
365 namespace eprosima {
366 
367 using std::shared_mutex;
368 using std::shared_lock;
369 
370 } //namespace eprosima
371 
372 #endif // if (__cplusplus < 201402) || (defined(_MSC_VER) && _MSC_VER < 1900 )
373 
374 #endif // _UTILS_SHARED_MUTEX_HPP_
Definition: shared_mutex.hpp:158
shared_lock(mutex_type &m, const std::chrono::duration< Rep, Period > &rel_time)
Definition: shared_mutex.hpp:223
bool try_lock_until(const std::chrono::time_point< Clock, Duration > &abs_time)
shared_lock(shared_lock &&sl)
Definition: shared_mutex.hpp:244
void swap(shared_lock &&u)
Definition: shared_mutex.hpp:293
shared_lock(mutex_type &m)
Definition: shared_mutex.hpp:181
mutex_type * mutex() const
Definition: shared_mutex.hpp:316
Mutex mutex_type
Definition: shared_mutex.hpp:161
shared_lock()
Definition: shared_mutex.hpp:175
bool try_lock_for(const std::chrono::duration< Rep, Period > &rel_time)
Definition: shared_mutex.hpp:281
shared_lock(std::unique_lock< mutex_type > &&ul)
Definition: shared_mutex.hpp:266
shared_lock(mutex_type &m, std::adopt_lock_t)
Definition: shared_mutex.hpp:205
shared_lock(shared_lock const &)=delete
bool try_lock()
Definition: shared_mutex.hpp:343
void lock()
Definition: shared_mutex.hpp:325
shared_lock(mutex_type &m, std::try_to_lock_t)
Definition: shared_mutex.hpp:197
shared_lock(mutex_type &m, const std::chrono::time_point< Clock, Duration > &abs_time)
Definition: shared_mutex.hpp:214
bool owns_lock() const
Definition: shared_mutex.hpp:308
mutex_type * release()
Definition: shared_mutex.hpp:300
shared_lock(mutex_type &m, std::defer_lock_t)
Definition: shared_mutex.hpp:189
~shared_lock()
Definition: shared_mutex.hpp:231
shared_lock & operator=(shared_lock const &)=delete
Definition: shared_mutex.hpp:40
bool try_lock_shared()
Definition: shared_mutex.hpp:118
~shared_mutex()
Definition: shared_mutex.hpp:60
void unlock_shared()
Definition: shared_mutex.hpp:132
void lock_shared()
Definition: shared_mutex.hpp:106
shared_mutex & operator=(const shared_mutex &)=delete
shared_mutex()
Definition: shared_mutex.hpp:55
shared_mutex(const shared_mutex &)=delete
void unlock()
Definition: shared_mutex.hpp:97
bool try_lock()
Definition: shared_mutex.hpp:86
void lock()
Definition: shared_mutex.hpp:72
eProsima namespace.
Definition: LibrarySettingsAttributes.h:23