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_USE_C99_STDINT_TR1 50 #ifdef _GLIBCXX_HAS_GTHREADS 52 #if __cplusplus >= 201703L 53 #define __cpp_lib_shared_mutex 201505 57 #define __cpp_lib_shared_timed_mutex 201402 58 class shared_timed_mutex;
60 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T 62 class __shared_mutex_pthread
64 friend class shared_timed_mutex;
66 #ifdef PTHREAD_RWLOCK_INITIALIZER 67 pthread_rwlock_t _M_rwlock = PTHREAD_RWLOCK_INITIALIZER;
70 __shared_mutex_pthread() =
default;
71 ~__shared_mutex_pthread() =
default;
73 pthread_rwlock_t _M_rwlock;
76 __shared_mutex_pthread()
78 int __ret = pthread_rwlock_init(&_M_rwlock, NULL);
81 else if (__ret == EAGAIN)
82 __throw_system_error(
int(errc::resource_unavailable_try_again));
83 else if (__ret == EPERM)
84 __throw_system_error(
int(errc::operation_not_permitted));
86 __glibcxx_assert(__ret == 0);
89 ~__shared_mutex_pthread()
91 int __ret __attribute((__unused__)) = pthread_rwlock_destroy(&_M_rwlock);
93 __glibcxx_assert(__ret == 0);
97 __shared_mutex_pthread(
const __shared_mutex_pthread&) =
delete;
98 __shared_mutex_pthread& operator=(
const __shared_mutex_pthread&) =
delete;
103 int __ret = pthread_rwlock_wrlock(&_M_rwlock);
104 if (__ret == EDEADLK)
105 __throw_system_error(
int(errc::resource_deadlock_would_occur));
107 __glibcxx_assert(__ret == 0);
113 int __ret = pthread_rwlock_trywrlock(&_M_rwlock);
114 if (__ret == EBUSY)
return false;
116 __glibcxx_assert(__ret == 0);
123 int __ret __attribute((__unused__)) = pthread_rwlock_unlock(&_M_rwlock);
125 __glibcxx_assert(__ret == 0);
139 __ret = pthread_rwlock_rdlock(&_M_rwlock);
140 while (__ret == EAGAIN);
141 if (__ret == EDEADLK)
142 __throw_system_error(
int(errc::resource_deadlock_would_occur));
144 __glibcxx_assert(__ret == 0);
150 int __ret = pthread_rwlock_tryrdlock(&_M_rwlock);
154 if (__ret == EBUSY || __ret == EAGAIN)
return false;
156 __glibcxx_assert(__ret == 0);
166 void* native_handle() {
return &_M_rwlock; }
170 #if ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK) 210 static constexpr
unsigned _S_write_entered
211 = 1U << (
sizeof(unsigned)*__CHAR_BIT__ - 1);
212 static constexpr
unsigned _S_max_readers = ~_S_write_entered;
215 bool _M_write_entered()
const {
return _M_state & _S_write_entered; }
218 unsigned _M_readers()
const {
return _M_state & _S_max_readers; }
225 __glibcxx_assert( _M_state == 0 );
238 _M_gate1.wait(__lk, [=]{
return !_M_write_entered(); });
239 _M_state |= _S_write_entered;
241 _M_gate2.wait(__lk, [=]{
return _M_readers() == 0; });
248 if (__lk.owns_lock() && _M_state == 0)
250 _M_state = _S_write_entered;
260 __glibcxx_assert( _M_write_entered() );
264 _M_gate1.notify_all();
273 _M_gate1.wait(__lk, [=]{
return _M_state < _S_max_readers; });
281 if (!__lk.owns_lock())
283 if (_M_state < _S_max_readers)
295 __glibcxx_assert( _M_readers() > 0 );
296 auto __prev = _M_state--;
297 if (_M_write_entered())
300 if (_M_readers() == 0)
301 _M_gate2.notify_one();
309 if (__prev == _S_max_readers)
310 _M_gate1.notify_one();
316 #if __cplusplus > 201402L 321 shared_mutex() =
default;
322 ~shared_mutex() =
default;
324 shared_mutex(
const shared_mutex&) =
delete;
325 shared_mutex& operator=(
const shared_mutex&) =
delete;
329 void lock() { _M_impl.lock(); }
330 bool try_lock() {
return _M_impl.try_lock(); }
331 void unlock() { _M_impl.unlock(); }
335 void lock_shared() { _M_impl.lock_shared(); }
336 bool try_lock_shared() {
return _M_impl.try_lock_shared(); }
337 void unlock_shared() { _M_impl.unlock_shared(); }
339 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T 340 typedef void* native_handle_type;
341 native_handle_type native_handle() {
return _M_impl.native_handle(); }
344 __shared_mutex_pthread _M_impl;
352 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK 365 typedef chrono::system_clock __clock_t;
378 void unlock() { _Base::unlock(); }
380 template<
typename _Rep,
typename _Period>
384 return try_lock_until(__clock_t::now() + __rel_time);
389 void lock_shared() { _Base::lock_shared(); }
390 bool try_lock_shared() {
return _Base::try_lock_shared(); }
391 void unlock_shared() { _Base::unlock_shared(); }
393 template<
typename _Rep,
typename _Period>
397 return try_lock_shared_until(__clock_t::now() + __rel_time);
400 #if _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK 404 template<
typename _Duration>
411 __gthread_time_t __ts =
413 static_cast<std::time_t
>(__s.time_since_epoch().count()),
414 static_cast<long>(__ns.count())
417 int __ret = pthread_rwlock_timedwrlock(&_M_rwlock, &__ts);
420 if (__ret == ETIMEDOUT || __ret == EDEADLK)
423 __glibcxx_assert(__ret == 0);
427 template<
typename _Clock,
typename _Duration>
432 const typename _Clock::time_point __c_entry = _Clock::now();
433 const __clock_t::time_point __s_entry = __clock_t::now();
434 const auto __delta = __abs_time - __c_entry;
435 const auto __s_atime = __s_entry + __delta;
436 return try_lock_until(__s_atime);
441 template<
typename _Duration>
449 __gthread_time_t __ts =
451 static_cast<std::time_t
>(__s.time_since_epoch().count()),
452 static_cast<long>(__ns.count())
470 __ret = pthread_rwlock_timedrdlock(&_M_rwlock, &__ts);
471 while (__ret == EAGAIN || __ret == EDEADLK);
472 if (__ret == ETIMEDOUT)
475 __glibcxx_assert(__ret == 0);
479 template<
typename _Clock,
typename _Duration>
482 _Duration>& __abs_time)
485 const typename _Clock::time_point __c_entry = _Clock::now();
486 const __clock_t::time_point __s_entry = __clock_t::now();
487 const auto __delta = __abs_time - __c_entry;
488 const auto __s_atime = __s_entry + __delta;
489 return try_lock_shared_until(__s_atime);
492 #else // ! (_GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK) 496 template<
typename _Clock,
typename _Duration>
501 if (!_M_gate1.wait_until(__lk, __abs_time,
502 [=]{ return !_M_write_entered(); }))
506 _M_state |= _S_write_entered;
507 if (!_M_gate2.wait_until(__lk, __abs_time,
508 [=]{ return _M_readers() == 0; }))
510 _M_state ^= _S_write_entered;
512 _M_gate1.notify_all();
520 template <
typename _Clock,
typename _Duration>
523 _Duration>& __abs_time)
526 if (!_M_gate1.wait_until(__lk, __abs_time,
527 [=]{ return _M_state < _S_max_readers; }))
535 #endif // _GLIBCXX_USE_PTHREAD_RWLOCK_T && _GTHREAD_USE_MUTEX_TIMEDLOCK 537 #endif // _GLIBCXX_HAS_GTHREADS 540 template<
typename _Mutex>
544 typedef _Mutex mutex_type;
548 shared_lock() noexcept : _M_pm(
nullptr), _M_owns(
false) { }
553 { __m.lock_shared(); }
564 template<
typename _Clock,
typename _Duration>
568 _M_owns(__m.try_lock_shared_until(__abs_time)) { }
570 template<
typename _Rep,
typename _Period>
574 _M_owns(__m.try_lock_shared_for(__rel_time)) { }
579 _M_pm->unlock_shared();
599 _M_pm->lock_shared();
607 return _M_owns = _M_pm->try_lock_shared();
610 template<
typename _Rep,
typename _Period>
615 return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
618 template<
typename _Clock,
typename _Duration>
623 return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
630 __throw_system_error(
int(errc::resource_deadlock_would_occur));
631 _M_pm->unlock_shared();
640 std::swap(_M_pm, __u._M_pm);
641 std::swap(_M_owns, __u._M_owns);
653 bool owns_lock()
const noexcept {
return _M_owns; }
655 explicit operator bool()
const noexcept {
return _M_owns; }
657 mutex_type*
mutex()
const noexcept {
return _M_pm; }
663 if (_M_pm ==
nullptr)
664 __throw_system_error(
int(errc::operation_not_permitted));
666 __throw_system_error(
int(errc::resource_deadlock_would_occur));
674 template<
typename _Mutex>
679 #endif // _GLIBCXX_USE_C99_STDINT_TR1 682 _GLIBCXX_END_NAMESPACE_VERSION
687 #endif // _GLIBCXX_SHARED_MUTEX constexpr enable_if< __is_duration< _ToDur >::value, time_point< _Clock, _ToDur > >::type time_point_cast(const time_point< _Clock, _Dur > &__t)
time_point_cast
void lock(_L1 &__l1, _L2 &__l2, _L3 &... __l3)
Generic lock.
_Tp exchange(_Tp &__obj, _Up &&__new_val)
Assign __new_val to __obj and return its previous value.
A shared mutex type implemented using std::condition_variable.
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
_GLIBCXX17_INLINE constexpr try_to_lock_t try_to_lock
Tag used to prevent a scoped lock from blocking if a mutex is locked.
__shared_mutex_cv __shared_timed_mutex_base
Swap specialization for shared_lock.
A movable scoped lock type.
ISO C++ entities toplevel namespace is std.
Try to acquire ownership of the mutex without blocking.
constexpr __enable_if_is_duration< _ToDur > duration_cast(const duration< _Rep, _Period > &__d)
duration_cast
A simple scoped lock type.
Do not acquire ownership of the mutex.
The standard shared timed mutex type.
Assume the calling thread has already obtained mutex ownership and manage it.
int try_lock(_Lock1 &__l1, _Lock2 &__l2, _Lock3 &... __l3)
Generic try_lock.