29 #ifndef _GLIBCXX_SHARED_MUTEX
30 #define _GLIBCXX_SHARED_MUTEX 1
32 #pragma GCC system_header
34 #if __cplusplus >= 201402L
40 namespace std _GLIBCXX_VISIBILITY(default)
42 _GLIBCXX_BEGIN_NAMESPACE_VERSION
49 #ifdef _GLIBCXX_HAS_GTHREADS
51 #if __cplusplus >= 201703L
52 #define __cpp_lib_shared_mutex 201505
56 #define __cpp_lib_shared_timed_mutex 201402
57 class shared_timed_mutex;
61 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T
63 #define _GLIBCXX_GTHRW(name) \
64 __gthrw(pthread_ ## name); \
66 __glibcxx_ ## name (pthread_rwlock_t *__rwlock) \
68 if (__gthread_active_p ()) \
69 return __gthrw_(pthread_ ## name) (__rwlock); \
73 _GLIBCXX_GTHRW(rwlock_rdlock)
74 _GLIBCXX_GTHRW(rwlock_tryrdlock)
75 _GLIBCXX_GTHRW(rwlock_wrlock)
76 _GLIBCXX_GTHRW(rwlock_trywrlock)
77 _GLIBCXX_GTHRW(rwlock_unlock)
78 # ifndef PTHREAD_RWLOCK_INITIALIZER
79 _GLIBCXX_GTHRW(rwlock_destroy)
80 __gthrw(pthread_rwlock_init);
82 __glibcxx_rwlock_init (pthread_rwlock_t *__rwlock)
84 if (__gthread_active_p ())
85 return __gthrw_(pthread_rwlock_init) (__rwlock, NULL);
90 # if _GTHREAD_USE_MUTEX_TIMEDLOCK
91 __gthrw(pthread_rwlock_timedrdlock);
93 __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,
96 if (__gthread_active_p ())
97 return __gthrw_(pthread_rwlock_timedrdlock) (__rwlock, __ts);
101 __gthrw(pthread_rwlock_timedwrlock);
103 __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,
104 const timespec *__ts)
106 if (__gthread_active_p ())
107 return __gthrw_(pthread_rwlock_timedwrlock) (__rwlock, __ts);
114 __glibcxx_rwlock_rdlock (pthread_rwlock_t *__rwlock)
115 {
return pthread_rwlock_rdlock (__rwlock); }
117 __glibcxx_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
118 {
return pthread_rwlock_tryrdlock (__rwlock); }
120 __glibcxx_rwlock_wrlock (pthread_rwlock_t *__rwlock)
121 {
return pthread_rwlock_wrlock (__rwlock); }
123 __glibcxx_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
124 {
return pthread_rwlock_trywrlock (__rwlock); }
126 __glibcxx_rwlock_unlock (pthread_rwlock_t *__rwlock)
127 {
return pthread_rwlock_unlock (__rwlock); }
129 __glibcxx_rwlock_destroy(pthread_rwlock_t *__rwlock)
130 {
return pthread_rwlock_destroy (__rwlock); }
132 __glibcxx_rwlock_init(pthread_rwlock_t *__rwlock)
133 {
return pthread_rwlock_init (__rwlock, NULL); }
134 # if _GTHREAD_USE_MUTEX_TIMEDLOCK
136 __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,
137 const timespec *__ts)
138 {
return pthread_rwlock_timedrdlock (__rwlock, __ts); }
140 __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,
141 const timespec *__ts)
142 {
return pthread_rwlock_timedwrlock (__rwlock, __ts); }
147 class __shared_mutex_pthread
149 friend class shared_timed_mutex;
151 #ifdef PTHREAD_RWLOCK_INITIALIZER
152 pthread_rwlock_t _M_rwlock = PTHREAD_RWLOCK_INITIALIZER;
155 __shared_mutex_pthread() =
default;
156 ~__shared_mutex_pthread() =
default;
158 pthread_rwlock_t _M_rwlock;
161 __shared_mutex_pthread()
163 int __ret = __glibcxx_rwlock_init(&_M_rwlock);
166 else if (__ret == EAGAIN)
167 __throw_system_error(
int(errc::resource_unavailable_try_again));
168 else if (__ret == EPERM)
169 __throw_system_error(
int(errc::operation_not_permitted));
171 __glibcxx_assert(__ret == 0);
174 ~__shared_mutex_pthread()
176 int __ret __attribute((__unused__)) = __glibcxx_rwlock_destroy(&_M_rwlock);
178 __glibcxx_assert(__ret == 0);
182 __shared_mutex_pthread(
const __shared_mutex_pthread&) =
delete;
183 __shared_mutex_pthread& operator=(
const __shared_mutex_pthread&) =
delete;
188 int __ret = __glibcxx_rwlock_wrlock(&_M_rwlock);
189 if (__ret == EDEADLK)
190 __throw_system_error(
int(errc::resource_deadlock_would_occur));
192 __glibcxx_assert(__ret == 0);
198 int __ret = __glibcxx_rwlock_trywrlock(&_M_rwlock);
199 if (__ret == EBUSY)
return false;
201 __glibcxx_assert(__ret == 0);
208 int __ret __attribute((__unused__)) = __glibcxx_rwlock_unlock(&_M_rwlock);
210 __glibcxx_assert(__ret == 0);
224 __ret = __glibcxx_rwlock_rdlock(&_M_rwlock);
225 while (__ret == EAGAIN);
226 if (__ret == EDEADLK)
227 __throw_system_error(
int(errc::resource_deadlock_would_occur));
229 __glibcxx_assert(__ret == 0);
235 int __ret = __glibcxx_rwlock_tryrdlock(&_M_rwlock);
239 if (__ret == EBUSY || __ret == EAGAIN)
return false;
241 __glibcxx_assert(__ret == 0);
251 void* native_handle() {
return &_M_rwlock; }
255 #if ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK)
257 class __shared_mutex_cv
259 friend class shared_timed_mutex;
289 condition_variable _M_gate1;
291 condition_variable _M_gate2;
295 static constexpr
unsigned _S_write_entered
296 = 1U << (
sizeof(unsigned)*__CHAR_BIT__ - 1);
297 static constexpr
unsigned _S_max_readers = ~_S_write_entered;
300 bool _M_write_entered()
const {
return _M_state & _S_write_entered; }
303 unsigned _M_readers()
const {
return _M_state & _S_max_readers; }
306 __shared_mutex_cv() : _M_state(0) {}
310 __glibcxx_assert( _M_state == 0 );
313 __shared_mutex_cv(
const __shared_mutex_cv&) =
delete;
314 __shared_mutex_cv& operator=(
const __shared_mutex_cv&) =
delete;
321 unique_lock<mutex> __lk(_M_mut);
323 _M_gate1.wait(__lk, [=]{
return !_M_write_entered(); });
324 _M_state |= _S_write_entered;
326 _M_gate2.wait(__lk, [=]{
return _M_readers() == 0; });
333 if (__lk.owns_lock() && _M_state == 0)
335 _M_state = _S_write_entered;
344 lock_guard<mutex> __lk(_M_mut);
345 __glibcxx_assert( _M_write_entered() );
349 _M_gate1.notify_all();
357 unique_lock<mutex> __lk(_M_mut);
358 _M_gate1.wait(__lk, [=]{
return _M_state < _S_max_readers; });
366 if (!__lk.owns_lock())
368 if (_M_state < _S_max_readers)
379 lock_guard<mutex> __lk(_M_mut);
380 __glibcxx_assert( _M_readers() > 0 );
381 auto __prev = _M_state--;
382 if (_M_write_entered())
385 if (_M_readers() == 0)
386 _M_gate2.notify_one();
394 if (__prev == _S_max_readers)
395 _M_gate1.notify_one();
402 #if __cplusplus > 201402L
407 shared_mutex() =
default;
408 ~shared_mutex() =
default;
410 shared_mutex(
const shared_mutex&) =
delete;
411 shared_mutex& operator=(
const shared_mutex&) =
delete;
415 void lock() { _M_impl.lock(); }
416 bool try_lock() {
return _M_impl.try_lock(); }
417 void unlock() { _M_impl.unlock(); }
421 void lock_shared() { _M_impl.lock_shared(); }
422 bool try_lock_shared() {
return _M_impl.try_lock_shared(); }
423 void unlock_shared() { _M_impl.unlock_shared(); }
425 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T
426 typedef void* native_handle_type;
427 native_handle_type native_handle() {
return _M_impl.native_handle(); }
430 __shared_mutex_pthread _M_impl;
433 __shared_mutex_cv _M_impl;
439 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK
440 using __shared_timed_mutex_base = __shared_mutex_pthread;
442 using __shared_timed_mutex_base = __shared_mutex_cv;
448 :
private __shared_timed_mutex_base
450 using _Base = __shared_timed_mutex_base;
453 #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
470 void unlock() { _Base::unlock(); }
472 template<
typename _Rep,
typename _Period>
476 auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime);
479 return try_lock_until(__clock_t::now() + __rt);
484 void lock_shared() { _Base::lock_shared(); }
485 bool try_lock_shared() {
return _Base::try_lock_shared(); }
486 void unlock_shared() { _Base::unlock_shared(); }
488 template<
typename _Rep,
typename _Period>
492 auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime);
495 return try_lock_shared_until(__clock_t::now() + __rt);
498 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK
502 template<
typename _Duration>
507 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
508 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
510 __gthread_time_t __ts =
512 static_cast<std::time_t
>(__s.time_since_epoch().count()),
513 static_cast<long>(__ns.count())
516 int __ret = __glibcxx_rwlock_timedwrlock(&_M_rwlock, &__ts);
519 if (__ret == ETIMEDOUT || __ret == EDEADLK)
522 __glibcxx_assert(__ret == 0);
526 #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
527 template<
typename _Duration>
532 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
533 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
535 __gthread_time_t __ts =
537 static_cast<std::time_t
>(__s.time_since_epoch().count()),
538 static_cast<long>(__ns.count())
541 int __ret = pthread_rwlock_clockwrlock(&_M_rwlock, CLOCK_MONOTONIC,
545 if (__ret == ETIMEDOUT || __ret == EDEADLK)
548 __glibcxx_assert(__ret == 0);
553 template<
typename _Clock,
typename _Duration>
557 #if __cplusplus > 201703L
558 static_assert(chrono::is_clock_v<_Clock>);
563 typename _Clock::time_point __now = _Clock::now();
565 auto __rtime = __atime - __now;
566 if (try_lock_for(__rtime))
568 __now = _Clock::now();
569 }
while (__atime > __now);
575 template<
typename _Duration>
580 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
581 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
583 __gthread_time_t __ts =
585 static_cast<std::time_t
>(__s.time_since_epoch().count()),
586 static_cast<long>(__ns.count())
604 __ret = __glibcxx_rwlock_timedrdlock(&_M_rwlock, &__ts);
605 while (__ret == EAGAIN || __ret == EDEADLK);
606 if (__ret == ETIMEDOUT)
609 __glibcxx_assert(__ret == 0);
613 #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
614 template<
typename _Duration>
619 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
620 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
622 __gthread_time_t __ts =
624 static_cast<std::time_t
>(__s.time_since_epoch().count()),
625 static_cast<long>(__ns.count())
628 int __ret = pthread_rwlock_clockrdlock(&_M_rwlock, CLOCK_MONOTONIC,
632 if (__ret == ETIMEDOUT || __ret == EDEADLK)
635 __glibcxx_assert(__ret == 0);
640 template<
typename _Clock,
typename _Duration>
645 #if __cplusplus > 201703L
646 static_assert(chrono::is_clock_v<_Clock>);
651 typename _Clock::time_point __now = _Clock::now();
653 auto __rtime = __atime - __now;
654 if (try_lock_shared_for(__rtime))
656 __now = _Clock::now();
657 }
while (__atime > __now);
665 template<
typename _Clock,
typename _Duration>
670 if (!_M_gate1.wait_until(__lk, __abs_time,
671 [=]{ return !_M_write_entered(); }))
675 _M_state |= _S_write_entered;
676 if (!_M_gate2.wait_until(__lk, __abs_time,
677 [=]{ return _M_readers() == 0; }))
679 _M_state ^= _S_write_entered;
681 _M_gate1.notify_all();
689 template <
typename _Clock,
typename _Duration>
692 _Duration>& __abs_time)
695 if (!_M_gate1.wait_until(__lk, __abs_time,
696 [=]{ return _M_state < _S_max_readers; }))
709 template<
typename _Mutex>
713 typedef _Mutex mutex_type;
717 shared_lock() noexcept : _M_pm(
nullptr), _M_owns(
false) { }
722 { __m.lock_shared(); }
733 template<
typename _Clock,
typename _Duration>
737 _M_owns(__m.try_lock_shared_until(__abs_time)) { }
739 template<
typename _Rep,
typename _Period>
743 _M_owns(__m.try_lock_shared_for(__rel_time)) { }
748 _M_pm->unlock_shared();
768 _M_pm->lock_shared();
776 return _M_owns = _M_pm->try_lock_shared();
779 template<
typename _Rep,
typename _Period>
784 return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
787 template<
typename _Clock,
typename _Duration>
792 return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
799 __throw_system_error(
int(errc::resource_deadlock_would_occur));
800 _M_pm->unlock_shared();
809 std::swap(_M_pm, __u._M_pm);
810 std::swap(_M_owns, __u._M_owns);
822 bool owns_lock()
const noexcept {
return _M_owns; }
824 explicit operator bool()
const noexcept {
return _M_owns; }
826 mutex_type*
mutex()
const noexcept {
return _M_pm; }
832 if (_M_pm ==
nullptr)
833 __throw_system_error(
int(errc::operation_not_permitted));
835 __throw_system_error(
int(errc::resource_deadlock_would_occur));
844 template<
typename _Mutex>
850 _GLIBCXX_END_NAMESPACE_VERSION
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
void lock(_L1 &__l1, _L2 &__l2, _L3 &... __l3)
Generic lock.
constexpr try_to_lock_t try_to_lock
Tag used to prevent a scoped lock from blocking if a mutex is locked.
int try_lock(_Lock1 &__l1, _Lock2 &__l2, _Lock3 &... __l3)
Generic try_lock.
ISO C++ entities toplevel namespace is std.
constexpr _Tp exchange(_Tp &__obj, _Up &&__new_val)
Assign __new_val to __obj and return its previous value.
The standard shared timed mutex type.
Do not acquire ownership of the mutex.
Try to acquire ownership of the mutex without blocking.
Assume the calling thread has already obtained mutex ownership and manage it.
A movable scoped lock type.