22#if ((__cplusplus >= 201703L) || (defined(_MSC_VER) && _MSC_VER >= 1900))
23#include <shared_mutex>
29#include <condition_variable>
30#include <system_error>
32#if (defined(__USE_UNIX98) || defined(__USE_XOPEN2K))
33#define HAVE_PTHREAD_RWLOCK
38#define THROW_OR_ABORT(exception) (throw(exception))
41#define THROW_OR_ABORT(exception) \
53template <
class T,
class U = T>
54T exchange(T& obj, U&& new_value) {
55 T old_value = std::move(obj);
56 obj = std::forward<U>(new_value);
60#if defined(HAVE_PTHREAD_RWLOCK)
63class shared_mutex_pthread {
64#if defined(PTHREAD_RWLOCK_INITIALIZER)
65 pthread_rwlock_t _M_rwlock = PTHREAD_RWLOCK_INITIALIZER;
68 shared_mutex_pthread() =
default;
69 ~shared_mutex_pthread() =
default;
71 pthread_rwlock_t _M_rwlock;
74 shared_mutex_pthread() {
75 int __ret = pthread_rwlock_init(&_M_rwlock, NULL);
77 THROW_OR_ABORT(std::bad_alloc());
78 else if (__ret == EAGAIN)
79 THROW_OR_ABORT(std::system_error(
80 std::make_error_code(errc::resource_unavailable_try_again)));
81 else if (__ret == EPERM)
82 THROW_OR_ABORT(std::system_error(
83 std::make_error_code(errc::operation_not_permitted)));
88 ~shared_mutex_pthread() {
89 int __ret __attribute((__unused__)) = pthread_rwlock_destroy(&_M_rwlock);
95 shared_mutex_pthread(
const shared_mutex_pthread&) =
delete;
96 shared_mutex_pthread& operator=(
const shared_mutex_pthread&) =
delete;
99 int __ret = pthread_rwlock_wrlock(&_M_rwlock);
100 if (__ret == EDEADLK)
101 THROW_OR_ABORT(std::system_error(
102 std::make_error_code(errc::resource_deadlock_would_occur)));
108 int __ret = pthread_rwlock_trywrlock(&_M_rwlock);
117 int __ret __attribute((__unused__)) = pthread_rwlock_unlock(&_M_rwlock);
131 __ret = pthread_rwlock_rdlock(&_M_rwlock);
132 }
while (__ret == EAGAIN);
133 if (__ret == EDEADLK)
134 THROW_OR_ABORT(std::system_error(
135 std::make_error_code(errc::resource_deadlock_would_occur)));
140 bool try_lock_shared() {
141 int __ret = pthread_rwlock_tryrdlock(&_M_rwlock);
145 if (__ret == EBUSY || __ret == EAGAIN)
152 void unlock_shared() { unlock(); }
154 void* native_handle() {
return &_M_rwlock; }
189 condition_variable _M_gate1;
191 condition_variable _M_gate2;
195 static constexpr unsigned _S_write_entered =
196 1U << (
sizeof(unsigned) * __CHAR_BIT__ - 1);
197 static constexpr unsigned _S_max_readers = ~_S_write_entered;
200 bool _M_write_entered()
const {
return _M_state & _S_write_entered; }
203 unsigned _M_readers()
const {
return _M_state & _S_max_readers; }
217 unique_lock<mutex> __lk(_M_mut);
219 _M_gate1.wait(__lk, [=] {
return !_M_write_entered(); });
220 _M_state |= _S_write_entered;
222 _M_gate2.wait(__lk, [=] {
return _M_readers() == 0; });
227 unique_lock<mutex> __lk(_M_mut, try_to_lock);
228 if (__lk.owns_lock() && _M_state == 0) {
229 _M_state = _S_write_entered;
237 lock_guard<mutex> __lk(_M_mut);
238 assert(_M_write_entered());
242 _M_gate1.notify_all();
249 unique_lock<mutex> __lk(_M_mut);
250 _M_gate1.wait(__lk, [=] {
return _M_state < _S_max_readers; });
256 unique_lock<mutex> __lk(_M_mut, try_to_lock);
257 if (!__lk.owns_lock())
259 if (_M_state < _S_max_readers) {
268 lock_guard<mutex> __lk(_M_mut);
269 assert(_M_readers() > 0);
270 auto __prev = _M_state--;
271 if (_M_write_entered()) {
273 if (_M_readers() == 0)
274 _M_gate2.notify_one();
280 if (__prev == _S_max_readers)
281 _M_gate1.notify_one();
329#if defined(HAVE_PTHREAD_RWLOCK)
330 typedef void* native_handle_type;
331 native_handle_type native_handle() {
return _M_impl.native_handle(); }
334 detail::shared_mutex_pthread _M_impl;
338 detail::shared_mutex_cv _M_impl;
345#if ((__cplusplus >= 201402L) || (defined(_MSC_VER) && _MSC_VER >= 1900))
346#include <shared_mutex>
351template <
typename Mutex>
359 typedef Mutex mutex_type;
361 shared_lock() noexcept : _M_pm(
nullptr), _M_owns(false) {}
369 explicit shared_lock(mutex_type& __m)
370 : _M_pm(std::addressof(__m)), _M_owns(true) {
380 shared_lock(mutex_type& __m, defer_lock_t) noexcept
381 : _M_pm(std::addressof(__m)), _M_owns(
false) {}
389 shared_lock(mutex_type& __m, try_to_lock_t)
390 : _M_pm(std::addressof(__m)), _M_owns(__m.try_lock_shared()) {}
398 shared_lock(mutex_type& __m, adopt_lock_t)
399 : _M_pm(std::addressof(__m)), _M_owns(true) {}
401 template <
typename _Clock,
typename _Duration>
410 shared_lock(mutex_type& __m,
411 const chrono::time_point<_Clock, _Duration>& __abs_time)
412 : _M_pm(std::addressof(__m)),
413 _M_owns(__m.try_lock_shared_until(__abs_time)) {}
415 template <
typename _Rep,
typename _Period>
424 shared_lock(mutex_type& __m,
425 const chrono::duration<_Rep, _Period>& __rel_time)
426 : _M_pm(std::addressof(__m)),
427 _M_owns(__m.try_lock_shared_for(__rel_time)) {}
431 _M_pm->unlock_shared();
434 shared_lock(shared_lock
const&) =
delete;
435 shared_lock& operator=(shared_lock
const&) =
delete;
442 shared_lock(shared_lock&& __sl) noexcept : shared_lock() { swap(__sl); }
449 shared_lock& operator=(shared_lock&& __sl)
noexcept {
450 shared_lock(std::move(__sl)).swap(*
this);
457 _M_pm->lock_shared();
464 return _M_owns = _M_pm->try_lock_shared();
467 template <
typename _Rep,
typename _Period>
477 bool try_lock_for(
const chrono::duration<_Rep, _Period>& __rel_time) {
479 return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
482 template <
typename _Clock,
typename _Duration>
492 bool try_lock_until(
const chrono::time_point<_Clock, _Duration>& __abs_time) {
494 return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
500 THROW_OR_ABORT(std::system_error(
501 std::make_error_code(errc::resource_deadlock_would_occur)));
502 _M_pm->unlock_shared();
511 void swap(shared_lock& __u)
noexcept {
512 std::swap(_M_pm, __u._M_pm);
513 std::swap(_M_owns, __u._M_owns);
522 mutex_type* release() noexcept {
524 return detail::exchange(_M_pm,
nullptr);
533 bool owns_lock() const noexcept {
return _M_owns; }
536 explicit operator bool() const noexcept {
return _M_owns; }
544 mutex_type* mutex() const noexcept {
return _M_pm; }
547 void _M_lockable()
const {
548 if (_M_pm ==
nullptr)
549 THROW_OR_ABORT(std::system_error(
550 std::make_error_code(errc::operation_not_permitted)));
552 THROW_OR_ABORT(std::system_error(
553 std::make_error_code(errc::resource_deadlock_would_occur)));
560template <
typename _Mutex>
561void swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y)
noexcept {
568#if defined(HAVE_PTHREAD_RWLOCK)
569#undef HAVE_PTHREAD_RWLOCK
A shared mutex type implemented using std::condition_variable.
Definition shared_mutex.h:160
void lock()
Takes ownership of the associated mutex.
Definition shared_mutex.h:216
bool try_lock()
Tries to take ownership of the mutex without blocking.
Definition shared_mutex.h:226
void lock_shared()
Blocks the calling thread until the thread obtains shared ownership of the mutex.
Definition shared_mutex.h:248
bool try_lock_shared()
Tries to take shared ownership of the mutex without blocking.
Definition shared_mutex.h:255
void unlock()
Releases the ownership of the mutex from the calling thread.
Definition shared_mutex.h:236
void unlock_shared()
Releases the shared ownership of the mutex from the calling thread.
Definition shared_mutex.h:267
A shared mutex type that can be locked exclusively by one thread or shared non-exclusively by multipl...
Definition shared_mutex.h:292
bool try_lock()
Tries to take ownership of the mutex without blocking.
Definition shared_mutex.h:308
bool try_lock_shared()
Tries to take shared ownership of the mutex without blocking.
Definition shared_mutex.h:324
void lock_shared()
Blocks the calling thread until the thread obtains shared ownership of the mutex.
Definition shared_mutex.h:317
void lock()
Takes ownership of the associated mutex.
Definition shared_mutex.h:301
void unlock_shared()
Releases the shared ownership of the mutex from the calling thread.
Definition shared_mutex.h:327
void unlock()
Releases the ownership of the mutex from the calling thread.
Definition shared_mutex.h:311