2 //===------------------------ shared_mutex --------------------------------===//
4 // The LLVM Compiler Infrastructure
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.TXT for details.
9 //===----------------------------------------------------------------------===//
11 #ifndef _LIBCPP_SHARED_MUTEX
12 #define _LIBCPP_SHARED_MUTEX
22 class shared_mutex // C++17
28 shared_mutex(const shared_mutex&) = delete;
29 shared_mutex& operator=(const shared_mutex&) = delete;
31 // Exclusive ownership
32 void lock(); // blocking
37 void lock_shared(); // blocking
38 bool try_lock_shared();
41 typedef implementation-defined native_handle_type; // See 30.2.3
42 native_handle_type native_handle(); // See 30.2.3
45 class shared_timed_mutex
49 ~shared_timed_mutex();
51 shared_timed_mutex(const shared_timed_mutex&) = delete;
52 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
54 // Exclusive ownership
55 void lock(); // blocking
57 template <class Rep, class Period>
58 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
59 template <class Clock, class Duration>
60 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
64 void lock_shared(); // blocking
65 bool try_lock_shared();
66 template <class Rep, class Period>
68 try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
69 template <class Clock, class Duration>
71 try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
75 template <class Mutex>
79 typedef Mutex mutex_type;
82 shared_lock() noexcept;
83 explicit shared_lock(mutex_type& m); // blocking
84 shared_lock(mutex_type& m, defer_lock_t) noexcept;
85 shared_lock(mutex_type& m, try_to_lock_t);
86 shared_lock(mutex_type& m, adopt_lock_t);
87 template <class Clock, class Duration>
88 shared_lock(mutex_type& m,
89 const chrono::time_point<Clock, Duration>& abs_time);
90 template <class Rep, class Period>
91 shared_lock(mutex_type& m,
92 const chrono::duration<Rep, Period>& rel_time);
95 shared_lock(shared_lock const&) = delete;
96 shared_lock& operator=(shared_lock const&) = delete;
98 shared_lock(shared_lock&& u) noexcept;
99 shared_lock& operator=(shared_lock&& u) noexcept;
101 void lock(); // blocking
103 template <class Rep, class Period>
104 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
105 template <class Clock, class Duration>
106 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
110 void swap(shared_lock& u) noexcept;
111 mutex_type* release() noexcept;
114 bool owns_lock() const noexcept;
115 explicit operator bool () const noexcept;
116 mutex_type* mutex() const noexcept;
119 template <class Mutex>
120 void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
129 #include <__undef_macros>
132 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
134 #include <__mutex_base>
136 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
137 #pragma GCC system_header
140 #ifdef _LIBCPP_HAS_NO_THREADS
141 #error <shared_mutex> is not supported on this single threaded system
142 #else // !_LIBCPP_HAS_NO_THREADS
144 _LIBCPP_BEGIN_NAMESPACE_STD
146 struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base
149 condition_variable __gate1_;
150 condition_variable __gate2_;
153 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
154 static const unsigned __n_readers_ = ~__write_entered_;
156 __shared_mutex_base();
157 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
159 __shared_mutex_base(const __shared_mutex_base&) = delete;
160 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
162 // Exclusive ownership
163 void lock(); // blocking
168 void lock_shared(); // blocking
169 bool try_lock_shared();
170 void unlock_shared();
172 // typedef implementation-defined native_handle_type; // See 30.2.3
173 // native_handle_type native_handle(); // See 30.2.3
177 #if _LIBCPP_STD_VER > 14
178 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
180 __shared_mutex_base __base;
182 _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
183 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
185 shared_mutex(const shared_mutex&) = delete;
186 shared_mutex& operator=(const shared_mutex&) = delete;
188 // Exclusive ownership
189 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
190 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
191 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
194 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
195 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
196 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
198 // typedef __shared_mutex_base::native_handle_type native_handle_type;
199 // _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
204 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
206 __shared_mutex_base __base;
208 shared_timed_mutex();
209 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
211 shared_timed_mutex(const shared_timed_mutex&) = delete;
212 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
214 // Exclusive ownership
217 template <class _Rep, class _Period>
218 _LIBCPP_INLINE_VISIBILITY
220 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
222 return try_lock_until(chrono::steady_clock::now() + __rel_time);
224 template <class _Clock, class _Duration>
225 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
227 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
232 bool try_lock_shared();
233 template <class _Rep, class _Period>
234 _LIBCPP_INLINE_VISIBILITY
236 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
238 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
240 template <class _Clock, class _Duration>
241 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
243 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
244 void unlock_shared();
247 template <class _Clock, class _Duration>
249 shared_timed_mutex::try_lock_until(
250 const chrono::time_point<_Clock, _Duration>& __abs_time)
252 unique_lock<mutex> __lk(__base.__mut_);
253 if (__base.__state_ & __base.__write_entered_)
257 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
258 if ((__base.__state_ & __base.__write_entered_) == 0)
260 if (__status == cv_status::timeout)
264 __base.__state_ |= __base.__write_entered_;
265 if (__base.__state_ & __base.__n_readers_)
269 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
270 if ((__base.__state_ & __base.__n_readers_) == 0)
272 if (__status == cv_status::timeout)
274 __base.__state_ &= ~__base.__write_entered_;
275 __base.__gate1_.notify_all();
283 template <class _Clock, class _Duration>
285 shared_timed_mutex::try_lock_shared_until(
286 const chrono::time_point<_Clock, _Duration>& __abs_time)
288 unique_lock<mutex> __lk(__base.__mut_);
289 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
293 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
294 if ((__base.__state_ & __base.__write_entered_) == 0 &&
295 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
297 if (status == cv_status::timeout)
301 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
302 __base.__state_ &= ~__base.__n_readers_;
303 __base.__state_ |= __num_readers;
307 template <class _Mutex>
311 typedef _Mutex mutex_type;
318 _LIBCPP_INLINE_VISIBILITY
319 shared_lock() _NOEXCEPT
324 _LIBCPP_INLINE_VISIBILITY
325 explicit shared_lock(mutex_type& __m)
326 : __m_(_VSTD::addressof(__m)),
328 {__m_->lock_shared();}
330 _LIBCPP_INLINE_VISIBILITY
331 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
332 : __m_(_VSTD::addressof(__m)),
336 _LIBCPP_INLINE_VISIBILITY
337 shared_lock(mutex_type& __m, try_to_lock_t)
338 : __m_(_VSTD::addressof(__m)),
339 __owns_(__m.try_lock_shared())
342 _LIBCPP_INLINE_VISIBILITY
343 shared_lock(mutex_type& __m, adopt_lock_t)
344 : __m_(_VSTD::addressof(__m)),
348 template <class _Clock, class _Duration>
349 _LIBCPP_INLINE_VISIBILITY
350 shared_lock(mutex_type& __m,
351 const chrono::time_point<_Clock, _Duration>& __abs_time)
352 : __m_(_VSTD::addressof(__m)),
353 __owns_(__m.try_lock_shared_until(__abs_time))
356 template <class _Rep, class _Period>
357 _LIBCPP_INLINE_VISIBILITY
358 shared_lock(mutex_type& __m,
359 const chrono::duration<_Rep, _Period>& __rel_time)
360 : __m_(_VSTD::addressof(__m)),
361 __owns_(__m.try_lock_shared_for(__rel_time))
364 _LIBCPP_INLINE_VISIBILITY
368 __m_->unlock_shared();
371 shared_lock(shared_lock const&) = delete;
372 shared_lock& operator=(shared_lock const&) = delete;
374 _LIBCPP_INLINE_VISIBILITY
375 shared_lock(shared_lock&& __u) _NOEXCEPT
383 _LIBCPP_INLINE_VISIBILITY
384 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
387 __m_->unlock_shared();
391 __owns_ = __u.__owns_;
399 template <class Rep, class Period>
400 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
401 template <class Clock, class Duration>
402 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
406 _LIBCPP_INLINE_VISIBILITY
407 void swap(shared_lock& __u) _NOEXCEPT
409 _VSTD::swap(__m_, __u.__m_);
410 _VSTD::swap(__owns_, __u.__owns_);
413 _LIBCPP_INLINE_VISIBILITY
414 mutex_type* release() _NOEXCEPT
416 mutex_type* __m = __m_;
423 _LIBCPP_INLINE_VISIBILITY
424 bool owns_lock() const _NOEXCEPT {return __owns_;}
426 _LIBCPP_INLINE_VISIBILITY
427 explicit operator bool () const _NOEXCEPT {return __owns_;}
429 _LIBCPP_INLINE_VISIBILITY
430 mutex_type* mutex() const _NOEXCEPT {return __m_;}
433 template <class _Mutex>
435 shared_lock<_Mutex>::lock()
438 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
440 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
445 template <class _Mutex>
447 shared_lock<_Mutex>::try_lock()
450 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
452 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
453 __owns_ = __m_->try_lock_shared();
457 template <class _Mutex>
458 template <class _Rep, class _Period>
460 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
463 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
465 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
466 __owns_ = __m_->try_lock_shared_for(__d);
470 template <class _Mutex>
471 template <class _Clock, class _Duration>
473 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
476 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
478 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
479 __owns_ = __m_->try_lock_shared_until(__t);
483 template <class _Mutex>
485 shared_lock<_Mutex>::unlock()
488 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
489 __m_->unlock_shared();
493 template <class _Mutex>
494 inline _LIBCPP_INLINE_VISIBILITY
496 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
499 _LIBCPP_END_NAMESPACE_STD
501 #endif // !_LIBCPP_HAS_NO_THREADS
503 #endif // _LIBCPP_STD_VER > 11
507 #endif // _LIBCPP_SHARED_MUTEX