Fast RTPS  Version 2.7.1
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
37namespace 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
53public:
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
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
156template <class Mutex>
158{
159public:
160
161 typedef Mutex mutex_type;
162
163private:
164
165 mutex_type* m_;
166 bool owns_;
167
168 struct __nat
169 {
170 int _;
171 };
172
173public:
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 }
317 {
318 return m_;
319 }
320
321};
322
323template <class Mutex>
324void
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
341template <class Mutex>
342bool
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
365namespace eprosima {
366
367using std::shared_mutex;
368using 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
mutex_type * release()
Definition: shared_mutex.hpp:300
mutex_type * mutex() const
Definition: shared_mutex.hpp:316
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 & operator=(shared_lock const &)=delete
shared_lock(mutex_type &m)
Definition: shared_mutex.hpp:181
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
shared_lock(mutex_type &m, std::defer_lock_t)
Definition: shared_mutex.hpp:189
~shared_lock()
Definition: shared_mutex.hpp:231
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()
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
shared_mutex & operator=(const shared_mutex &)=delete
eProsima namespace.
Definition: LibrarySettingsAttributes.h:23