2 //===------------------------ shared_mutex --------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP_SHARED_MUTEX
11 #define _LIBCPP_SHARED_MUTEX
21 class shared_mutex // C++17
27 shared_mutex(const shared_mutex&) = delete;
28 shared_mutex& operator=(const shared_mutex&) = delete;
30 // Exclusive ownership
31 void lock(); // blocking
36 void lock_shared(); // blocking
37 bool try_lock_shared();
40 typedef implementation-defined native_handle_type; // See 30.2.3
41 native_handle_type native_handle(); // See 30.2.3
44 class shared_timed_mutex
48 ~shared_timed_mutex();
50 shared_timed_mutex(const shared_timed_mutex&) = delete;
51 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
53 // Exclusive ownership
54 void lock(); // blocking
56 template <class Rep, class Period>
57 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
58 template <class Clock, class Duration>
59 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
63 void lock_shared(); // blocking
64 bool try_lock_shared();
65 template <class Rep, class Period>
67 try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
68 template <class Clock, class Duration>
70 try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
74 template <class Mutex>
78 typedef Mutex mutex_type;
81 shared_lock() noexcept;
82 explicit shared_lock(mutex_type& m); // blocking
83 shared_lock(mutex_type& m, defer_lock_t) noexcept;
84 shared_lock(mutex_type& m, try_to_lock_t);
85 shared_lock(mutex_type& m, adopt_lock_t);
86 template <class Clock, class Duration>
87 shared_lock(mutex_type& m,
88 const chrono::time_point<Clock, Duration>& abs_time);
89 template <class Rep, class Period>
90 shared_lock(mutex_type& m,
91 const chrono::duration<Rep, Period>& rel_time);
94 shared_lock(shared_lock const&) = delete;
95 shared_lock& operator=(shared_lock const&) = delete;
97 shared_lock(shared_lock&& u) noexcept;
98 shared_lock& operator=(shared_lock&& u) noexcept;
100 void lock(); // blocking
102 template <class Rep, class Period>
103 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
104 template <class Clock, class Duration>
105 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
109 void swap(shared_lock& u) noexcept;
110 mutex_type* release() noexcept;
113 bool owns_lock() const noexcept;
114 explicit operator bool () const noexcept;
115 mutex_type* mutex() const noexcept;
118 template <class Mutex>
119 void swap(shared_lock<Mutex>& x, shared_lock<Mutex>& y) noexcept;
125 #include <__availability>
130 #include <__undef_macros>
133 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
135 #include <__mutex_base>
137 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
138 #pragma GCC system_header
141 #ifdef _LIBCPP_HAS_NO_THREADS
142 #error <shared_mutex> is not supported on this single threaded system
143 #else // !_LIBCPP_HAS_NO_THREADS
145 _LIBCPP_BEGIN_NAMESPACE_STD
147 struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
151 condition_variable __gate1_;
152 condition_variable __gate2_;
155 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
156 static const unsigned __n_readers_ = ~__write_entered_;
158 __shared_mutex_base();
159 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
161 __shared_mutex_base(const __shared_mutex_base&) = delete;
162 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
164 // Exclusive ownership
165 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
166 bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
167 void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
170 void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
171 bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
172 void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
174 // typedef implementation-defined native_handle_type; // See 30.2.3
175 // native_handle_type native_handle(); // See 30.2.3
179 #if _LIBCPP_STD_VER > 14
180 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
182 __shared_mutex_base __base;
184 _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
185 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
187 shared_mutex(const shared_mutex&) = delete;
188 shared_mutex& operator=(const shared_mutex&) = delete;
190 // Exclusive ownership
191 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
192 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
193 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
196 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
197 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
198 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
200 // typedef __shared_mutex_base::native_handle_type native_handle_type;
201 // _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
206 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
208 __shared_mutex_base __base;
210 shared_timed_mutex();
211 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
213 shared_timed_mutex(const shared_timed_mutex&) = delete;
214 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
216 // Exclusive ownership
219 template <class _Rep, class _Period>
220 _LIBCPP_INLINE_VISIBILITY
222 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
224 return try_lock_until(chrono::steady_clock::now() + __rel_time);
226 template <class _Clock, class _Duration>
227 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
229 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
234 bool try_lock_shared();
235 template <class _Rep, class _Period>
236 _LIBCPP_INLINE_VISIBILITY
238 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
240 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
242 template <class _Clock, class _Duration>
243 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
245 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
246 void unlock_shared();
249 template <class _Clock, class _Duration>
251 shared_timed_mutex::try_lock_until(
252 const chrono::time_point<_Clock, _Duration>& __abs_time)
254 unique_lock<mutex> __lk(__base.__mut_);
255 if (__base.__state_ & __base.__write_entered_)
259 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
260 if ((__base.__state_ & __base.__write_entered_) == 0)
262 if (__status == cv_status::timeout)
266 __base.__state_ |= __base.__write_entered_;
267 if (__base.__state_ & __base.__n_readers_)
271 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
272 if ((__base.__state_ & __base.__n_readers_) == 0)
274 if (__status == cv_status::timeout)
276 __base.__state_ &= ~__base.__write_entered_;
277 __base.__gate1_.notify_all();
285 template <class _Clock, class _Duration>
287 shared_timed_mutex::try_lock_shared_until(
288 const chrono::time_point<_Clock, _Duration>& __abs_time)
290 unique_lock<mutex> __lk(__base.__mut_);
291 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
295 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
296 if ((__base.__state_ & __base.__write_entered_) == 0 &&
297 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
299 if (status == cv_status::timeout)
303 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
304 __base.__state_ &= ~__base.__n_readers_;
305 __base.__state_ |= __num_readers;
309 template <class _Mutex>
313 typedef _Mutex mutex_type;
320 _LIBCPP_INLINE_VISIBILITY
321 shared_lock() _NOEXCEPT
326 _LIBCPP_INLINE_VISIBILITY
327 explicit shared_lock(mutex_type& __m)
328 : __m_(_VSTD::addressof(__m)),
330 {__m_->lock_shared();}
332 _LIBCPP_INLINE_VISIBILITY
333 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
334 : __m_(_VSTD::addressof(__m)),
338 _LIBCPP_INLINE_VISIBILITY
339 shared_lock(mutex_type& __m, try_to_lock_t)
340 : __m_(_VSTD::addressof(__m)),
341 __owns_(__m.try_lock_shared())
344 _LIBCPP_INLINE_VISIBILITY
345 shared_lock(mutex_type& __m, adopt_lock_t)
346 : __m_(_VSTD::addressof(__m)),
350 template <class _Clock, class _Duration>
351 _LIBCPP_INLINE_VISIBILITY
352 shared_lock(mutex_type& __m,
353 const chrono::time_point<_Clock, _Duration>& __abs_time)
354 : __m_(_VSTD::addressof(__m)),
355 __owns_(__m.try_lock_shared_until(__abs_time))
358 template <class _Rep, class _Period>
359 _LIBCPP_INLINE_VISIBILITY
360 shared_lock(mutex_type& __m,
361 const chrono::duration<_Rep, _Period>& __rel_time)
362 : __m_(_VSTD::addressof(__m)),
363 __owns_(__m.try_lock_shared_for(__rel_time))
366 _LIBCPP_INLINE_VISIBILITY
370 __m_->unlock_shared();
373 shared_lock(shared_lock const&) = delete;
374 shared_lock& operator=(shared_lock const&) = delete;
376 _LIBCPP_INLINE_VISIBILITY
377 shared_lock(shared_lock&& __u) _NOEXCEPT
385 _LIBCPP_INLINE_VISIBILITY
386 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
389 __m_->unlock_shared();
393 __owns_ = __u.__owns_;
401 template <class Rep, class Period>
402 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
403 template <class Clock, class Duration>
404 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
408 _LIBCPP_INLINE_VISIBILITY
409 void swap(shared_lock& __u) _NOEXCEPT
411 _VSTD::swap(__m_, __u.__m_);
412 _VSTD::swap(__owns_, __u.__owns_);
415 _LIBCPP_INLINE_VISIBILITY
416 mutex_type* release() _NOEXCEPT
418 mutex_type* __m = __m_;
425 _LIBCPP_INLINE_VISIBILITY
426 bool owns_lock() const _NOEXCEPT {return __owns_;}
428 _LIBCPP_INLINE_VISIBILITY
429 explicit operator bool () const _NOEXCEPT {return __owns_;}
431 _LIBCPP_INLINE_VISIBILITY
432 mutex_type* mutex() const _NOEXCEPT {return __m_;}
435 template <class _Mutex>
437 shared_lock<_Mutex>::lock()
440 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
442 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
447 template <class _Mutex>
449 shared_lock<_Mutex>::try_lock()
452 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
454 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
455 __owns_ = __m_->try_lock_shared();
459 template <class _Mutex>
460 template <class _Rep, class _Period>
462 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
465 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
467 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
468 __owns_ = __m_->try_lock_shared_for(__d);
472 template <class _Mutex>
473 template <class _Clock, class _Duration>
475 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
478 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
480 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
481 __owns_ = __m_->try_lock_shared_until(__t);
485 template <class _Mutex>
487 shared_lock<_Mutex>::unlock()
490 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
491 __m_->unlock_shared();
495 template <class _Mutex>
496 inline _LIBCPP_INLINE_VISIBILITY
498 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
501 _LIBCPP_END_NAMESPACE_STD
503 #endif // !_LIBCPP_HAS_NO_THREADS
505 #endif // _LIBCPP_STD_VER > 11
509 #endif // _LIBCPP_SHARED_MUTEX