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