29 #ifndef _GLIBCXX_SHARED_MUTEX
30 #define _GLIBCXX_SHARED_MUTEX 1
32 #pragma GCC system_header
34 #if __cplusplus >= 201402L
41 #if ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK)
45 namespace std _GLIBCXX_VISIBILITY(default)
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
54 #ifdef _GLIBCXX_HAS_GTHREADS
56 #if __cplusplus >= 201703L
57 #define __cpp_lib_shared_mutex 201505L
61 #define __cpp_lib_shared_timed_mutex 201402L
62 class shared_timed_mutex;
66 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T
68 #define _GLIBCXX_GTHRW(name) \
69 __gthrw(pthread_ ## name); \
71 __glibcxx_ ## name (pthread_rwlock_t *__rwlock) \
73 if (__gthread_active_p ()) \
74 return __gthrw_(pthread_ ## name) (__rwlock); \
78 _GLIBCXX_GTHRW(rwlock_rdlock)
79 _GLIBCXX_GTHRW(rwlock_tryrdlock)
80 _GLIBCXX_GTHRW(rwlock_wrlock)
81 _GLIBCXX_GTHRW(rwlock_trywrlock)
82 _GLIBCXX_GTHRW(rwlock_unlock)
83 # ifndef PTHREAD_RWLOCK_INITIALIZER
84 _GLIBCXX_GTHRW(rwlock_destroy)
85 __gthrw(pthread_rwlock_init);
87 __glibcxx_rwlock_init (pthread_rwlock_t *__rwlock)
89 if (__gthread_active_p ())
90 return __gthrw_(pthread_rwlock_init) (__rwlock, NULL);
95 # if _GTHREAD_USE_MUTEX_TIMEDLOCK
96 __gthrw(pthread_rwlock_timedrdlock);
98 __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,
101 if (__gthread_active_p ())
102 return __gthrw_(pthread_rwlock_timedrdlock) (__rwlock, __ts);
106 __gthrw(pthread_rwlock_timedwrlock);
108 __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,
109 const timespec *__ts)
111 if (__gthread_active_p ())
112 return __gthrw_(pthread_rwlock_timedwrlock) (__rwlock, __ts);
119 __glibcxx_rwlock_rdlock (pthread_rwlock_t *__rwlock)
120 {
return pthread_rwlock_rdlock (__rwlock); }
122 __glibcxx_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
123 {
return pthread_rwlock_tryrdlock (__rwlock); }
125 __glibcxx_rwlock_wrlock (pthread_rwlock_t *__rwlock)
126 {
return pthread_rwlock_wrlock (__rwlock); }
128 __glibcxx_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
129 {
return pthread_rwlock_trywrlock (__rwlock); }
131 __glibcxx_rwlock_unlock (pthread_rwlock_t *__rwlock)
132 {
return pthread_rwlock_unlock (__rwlock); }
134 __glibcxx_rwlock_destroy(pthread_rwlock_t *__rwlock)
135 {
return pthread_rwlock_destroy (__rwlock); }
137 __glibcxx_rwlock_init(pthread_rwlock_t *__rwlock)
138 {
return pthread_rwlock_init (__rwlock, NULL); }
139 # if _GTHREAD_USE_MUTEX_TIMEDLOCK
141 __glibcxx_rwlock_timedrdlock (pthread_rwlock_t *__rwlock,
142 const timespec *__ts)
143 {
return pthread_rwlock_timedrdlock (__rwlock, __ts); }
145 __glibcxx_rwlock_timedwrlock (pthread_rwlock_t *__rwlock,
146 const timespec *__ts)
147 {
return pthread_rwlock_timedwrlock (__rwlock, __ts); }
152 class __shared_mutex_pthread
154 friend class shared_timed_mutex;
156 #ifdef PTHREAD_RWLOCK_INITIALIZER
157 pthread_rwlock_t _M_rwlock = PTHREAD_RWLOCK_INITIALIZER;
160 __shared_mutex_pthread() =
default;
161 ~__shared_mutex_pthread() =
default;
163 pthread_rwlock_t _M_rwlock;
166 __shared_mutex_pthread()
168 int __ret = __glibcxx_rwlock_init(&_M_rwlock);
171 else if (__ret == EAGAIN)
172 __throw_system_error(
int(errc::resource_unavailable_try_again));
173 else if (__ret == EPERM)
174 __throw_system_error(
int(errc::operation_not_permitted));
176 __glibcxx_assert(__ret == 0);
179 ~__shared_mutex_pthread()
181 int __ret __attribute((__unused__)) = __glibcxx_rwlock_destroy(&_M_rwlock);
183 __glibcxx_assert(__ret == 0);
187 __shared_mutex_pthread(
const __shared_mutex_pthread&) =
delete;
188 __shared_mutex_pthread& operator=(
const __shared_mutex_pthread&) =
delete;
193 int __ret = __glibcxx_rwlock_wrlock(&_M_rwlock);
194 if (__ret == EDEADLK)
195 __throw_system_error(
int(errc::resource_deadlock_would_occur));
197 __glibcxx_assert(__ret == 0);
203 int __ret = __glibcxx_rwlock_trywrlock(&_M_rwlock);
204 if (__ret == EBUSY)
return false;
206 __glibcxx_assert(__ret == 0);
213 int __ret __attribute((__unused__)) = __glibcxx_rwlock_unlock(&_M_rwlock);
215 __glibcxx_assert(__ret == 0);
229 __ret = __glibcxx_rwlock_rdlock(&_M_rwlock);
230 while (__ret == EAGAIN);
231 if (__ret == EDEADLK)
232 __throw_system_error(
int(errc::resource_deadlock_would_occur));
234 __glibcxx_assert(__ret == 0);
240 int __ret = __glibcxx_rwlock_tryrdlock(&_M_rwlock);
244 if (__ret == EBUSY || __ret == EAGAIN)
return false;
246 __glibcxx_assert(__ret == 0);
256 void* native_handle() {
return &_M_rwlock; }
260 #if ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK)
262 class __shared_mutex_cv
264 friend class shared_timed_mutex;
294 condition_variable _M_gate1;
296 condition_variable _M_gate2;
300 static constexpr
unsigned _S_write_entered
301 = 1U << (
sizeof(unsigned)*__CHAR_BIT__ - 1);
302 static constexpr
unsigned _S_max_readers = ~_S_write_entered;
305 bool _M_write_entered()
const {
return _M_state & _S_write_entered; }
308 unsigned _M_readers()
const {
return _M_state & _S_max_readers; }
311 __shared_mutex_cv() : _M_state(0) {}
315 __glibcxx_assert( _M_state == 0 );
318 __shared_mutex_cv(
const __shared_mutex_cv&) =
delete;
319 __shared_mutex_cv& operator=(
const __shared_mutex_cv&) =
delete;
326 unique_lock<mutex> __lk(_M_mut);
328 _M_gate1.wait(__lk, [=]{
return !_M_write_entered(); });
329 _M_state |= _S_write_entered;
331 _M_gate2.wait(__lk, [=]{
return _M_readers() == 0; });
338 if (__lk.owns_lock() && _M_state == 0)
340 _M_state = _S_write_entered;
349 lock_guard<mutex> __lk(_M_mut);
350 __glibcxx_assert( _M_write_entered() );
354 _M_gate1.notify_all();
362 unique_lock<mutex> __lk(_M_mut);
363 _M_gate1.wait(__lk, [=]{
return _M_state < _S_max_readers; });
371 if (!__lk.owns_lock())
373 if (_M_state < _S_max_readers)
384 lock_guard<mutex> __lk(_M_mut);
385 __glibcxx_assert( _M_readers() > 0 );
386 auto __prev = _M_state--;
387 if (_M_write_entered())
390 if (_M_readers() == 0)
391 _M_gate2.notify_one();
399 if (__prev == _S_max_readers)
400 _M_gate1.notify_one();
407 #if __cplusplus >= 201703L
420 void lock() { _M_impl.lock(); }
421 bool try_lock() {
return _M_impl.try_lock(); }
422 void unlock() { _M_impl.unlock(); }
426 void lock_shared() { _M_impl.lock_shared(); }
427 bool try_lock_shared() {
return _M_impl.try_lock_shared(); }
428 void unlock_shared() { _M_impl.unlock_shared(); }
430 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T
431 typedef void* native_handle_type;
432 native_handle_type native_handle() {
return _M_impl.native_handle(); }
435 __shared_mutex_pthread _M_impl;
438 __shared_mutex_cv _M_impl;
444 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK
445 using __shared_timed_mutex_base = __shared_mutex_pthread;
447 using __shared_timed_mutex_base = __shared_mutex_cv;
453 :
private __shared_timed_mutex_base
455 using _Base = __shared_timed_mutex_base;
458 #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
475 void unlock() { _Base::unlock(); }
477 template<
typename _Rep,
typename _Period>
481 auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime);
484 return try_lock_until(__clock_t::now() + __rt);
489 void lock_shared() { _Base::lock_shared(); }
490 bool try_lock_shared() {
return _Base::try_lock_shared(); }
491 void unlock_shared() { _Base::unlock_shared(); }
493 template<
typename _Rep,
typename _Period>
497 auto __rt = chrono::duration_cast<__clock_t::duration>(__rtime);
500 return try_lock_shared_until(__clock_t::now() + __rt);
503 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK
507 template<
typename _Duration>
512 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
513 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
515 __gthread_time_t __ts =
517 static_cast<std::time_t
>(__s.time_since_epoch().count()),
518 static_cast<long>(__ns.count())
521 int __ret = __glibcxx_rwlock_timedwrlock(&_M_rwlock, &__ts);
524 if (__ret == ETIMEDOUT || __ret == EDEADLK)
527 __glibcxx_assert(__ret == 0);
531 #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
532 template<
typename _Duration>
537 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
538 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
540 __gthread_time_t __ts =
542 static_cast<std::time_t
>(__s.time_since_epoch().count()),
543 static_cast<long>(__ns.count())
546 int __ret = pthread_rwlock_clockwrlock(&_M_rwlock, CLOCK_MONOTONIC,
550 if (__ret == ETIMEDOUT || __ret == EDEADLK)
553 __glibcxx_assert(__ret == 0);
558 template<
typename _Clock,
typename _Duration>
562 #if __cplusplus > 201703L
563 static_assert(chrono::is_clock_v<_Clock>);
568 typename _Clock::time_point __now = _Clock::now();
570 auto __rtime = __atime - __now;
571 if (try_lock_for(__rtime))
573 __now = _Clock::now();
574 }
while (__atime > __now);
580 template<
typename _Duration>
585 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
586 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
588 __gthread_time_t __ts =
590 static_cast<std::time_t
>(__s.time_since_epoch().count()),
591 static_cast<long>(__ns.count())
609 __ret = __glibcxx_rwlock_timedrdlock(&_M_rwlock, &__ts);
610 while (__ret == EAGAIN || __ret == EDEADLK);
611 if (__ret == ETIMEDOUT)
614 __glibcxx_assert(__ret == 0);
618 #ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
619 template<
typename _Duration>
624 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
625 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
627 __gthread_time_t __ts =
629 static_cast<std::time_t
>(__s.time_since_epoch().count()),
630 static_cast<long>(__ns.count())
633 int __ret = pthread_rwlock_clockrdlock(&_M_rwlock, CLOCK_MONOTONIC,
637 if (__ret == ETIMEDOUT || __ret == EDEADLK)
640 __glibcxx_assert(__ret == 0);
645 template<
typename _Clock,
typename _Duration>
650 #if __cplusplus > 201703L
651 static_assert(chrono::is_clock_v<_Clock>);
656 typename _Clock::time_point __now = _Clock::now();
658 auto __rtime = __atime - __now;
659 if (try_lock_shared_for(__rtime))
661 __now = _Clock::now();
662 }
while (__atime > __now);
670 template<
typename _Clock,
typename _Duration>
675 if (!_M_gate1.wait_until(__lk, __abs_time,
676 [=]{ return !_M_write_entered(); }))
680 _M_state |= _S_write_entered;
681 if (!_M_gate2.wait_until(__lk, __abs_time,
682 [=]{ return _M_readers() == 0; }))
684 _M_state ^= _S_write_entered;
686 _M_gate1.notify_all();
694 template <
typename _Clock,
typename _Duration>
697 _Duration>& __abs_time)
700 if (!_M_gate1.wait_until(__lk, __abs_time,
701 [=]{ return _M_state < _S_max_readers; }))
714 template<
typename _Mutex>
718 typedef _Mutex mutex_type;
722 shared_lock() noexcept : _M_pm(
nullptr), _M_owns(
false) { }
727 { __m.lock_shared(); }
738 template<
typename _Clock,
typename _Duration>
742 _M_owns(__m.try_lock_shared_until(__abs_time)) { }
744 template<
typename _Rep,
typename _Period>
748 _M_owns(__m.try_lock_shared_for(__rel_time)) { }
753 _M_pm->unlock_shared();
773 _M_pm->lock_shared();
781 return _M_owns = _M_pm->try_lock_shared();
784 template<
typename _Rep,
typename _Period>
789 return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
792 template<
typename _Clock,
typename _Duration>
797 return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
804 __throw_system_error(
int(errc::resource_deadlock_would_occur));
805 _M_pm->unlock_shared();
822 return std::__exchange(_M_pm,
nullptr);
827 bool owns_lock()
const noexcept {
return _M_owns; }
829 explicit operator bool()
const noexcept {
return _M_owns; }
831 mutex_type*
mutex()
const noexcept {
return _M_pm; }
837 if (_M_pm ==
nullptr)
838 __throw_system_error(
int(errc::operation_not_permitted));
840 __throw_system_error(
int(errc::resource_deadlock_would_occur));
849 template<
typename _Mutex>
855 _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 swap(any &__x, any &__y) noexcept
Exchange the states of two any objects.
void swap(shared_lock< _Mutex > &__x, shared_lock< _Mutex > &__y) noexcept
Swap specialization for shared_lock.
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.
chrono::duration represents a distance between two points in time
chrono::time_point represents a point in time as measured by a clock
The standard shared mutex type.
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.