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;
129 #include <__undef_macros>
132 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_LIBRARY)
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 _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex"))
150 condition_variable __gate1_;
151 condition_variable __gate2_;
154 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
155 static const unsigned __n_readers_ = ~__write_entered_;
157 __shared_mutex_base();
158 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
160 __shared_mutex_base(const __shared_mutex_base&) = delete;
161 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
163 // Exclusive ownership
164 void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
165 bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
166 void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
169 void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
170 bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
171 void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
173 // typedef implementation-defined native_handle_type; // See 30.2.3
174 // native_handle_type native_handle(); // See 30.2.3
178 #if _LIBCPP_STD_VER > 14
179 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex
181 __shared_mutex_base __base;
183 _LIBCPP_INLINE_VISIBILITY shared_mutex() : __base() {}
184 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
186 shared_mutex(const shared_mutex&) = delete;
187 shared_mutex& operator=(const shared_mutex&) = delete;
189 // Exclusive ownership
190 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
191 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
192 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
195 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
196 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
197 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
199 // typedef __shared_mutex_base::native_handle_type native_handle_type;
200 // _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
205 class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex
207 __shared_mutex_base __base;
209 shared_timed_mutex();
210 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
212 shared_timed_mutex(const shared_timed_mutex&) = delete;
213 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
215 // Exclusive ownership
218 template <class _Rep, class _Period>
219 _LIBCPP_INLINE_VISIBILITY
221 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
223 return try_lock_until(chrono::steady_clock::now() + __rel_time);
225 template <class _Clock, class _Duration>
226 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
228 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
233 bool try_lock_shared();
234 template <class _Rep, class _Period>
235 _LIBCPP_INLINE_VISIBILITY
237 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
239 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
241 template <class _Clock, class _Duration>
242 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
244 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
245 void unlock_shared();
248 template <class _Clock, class _Duration>
250 shared_timed_mutex::try_lock_until(
251 const chrono::time_point<_Clock, _Duration>& __abs_time)
253 unique_lock<mutex> __lk(__base.__mut_);
254 if (__base.__state_ & __base.__write_entered_)
258 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
259 if ((__base.__state_ & __base.__write_entered_) == 0)
261 if (__status == cv_status::timeout)
265 __base.__state_ |= __base.__write_entered_;
266 if (__base.__state_ & __base.__n_readers_)
270 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
271 if ((__base.__state_ & __base.__n_readers_) == 0)
273 if (__status == cv_status::timeout)
275 __base.__state_ &= ~__base.__write_entered_;
276 __base.__gate1_.notify_all();
284 template <class _Clock, class _Duration>
286 shared_timed_mutex::try_lock_shared_until(
287 const chrono::time_point<_Clock, _Duration>& __abs_time)
289 unique_lock<mutex> __lk(__base.__mut_);
290 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
294 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
295 if ((__base.__state_ & __base.__write_entered_) == 0 &&
296 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
298 if (status == cv_status::timeout)
302 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
303 __base.__state_ &= ~__base.__n_readers_;
304 __base.__state_ |= __num_readers;
308 template <class _Mutex>
312 typedef _Mutex mutex_type;
319 _LIBCPP_INLINE_VISIBILITY
320 shared_lock() _NOEXCEPT
325 _LIBCPP_INLINE_VISIBILITY
326 explicit shared_lock(mutex_type& __m)
327 : __m_(_VSTD::addressof(__m)),
329 {__m_->lock_shared();}
331 _LIBCPP_INLINE_VISIBILITY
332 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
333 : __m_(_VSTD::addressof(__m)),
337 _LIBCPP_INLINE_VISIBILITY
338 shared_lock(mutex_type& __m, try_to_lock_t)
339 : __m_(_VSTD::addressof(__m)),
340 __owns_(__m.try_lock_shared())
343 _LIBCPP_INLINE_VISIBILITY
344 shared_lock(mutex_type& __m, adopt_lock_t)
345 : __m_(_VSTD::addressof(__m)),
349 template <class _Clock, class _Duration>
350 _LIBCPP_INLINE_VISIBILITY
351 shared_lock(mutex_type& __m,
352 const chrono::time_point<_Clock, _Duration>& __abs_time)
353 : __m_(_VSTD::addressof(__m)),
354 __owns_(__m.try_lock_shared_until(__abs_time))
357 template <class _Rep, class _Period>
358 _LIBCPP_INLINE_VISIBILITY
359 shared_lock(mutex_type& __m,
360 const chrono::duration<_Rep, _Period>& __rel_time)
361 : __m_(_VSTD::addressof(__m)),
362 __owns_(__m.try_lock_shared_for(__rel_time))
365 _LIBCPP_INLINE_VISIBILITY
369 __m_->unlock_shared();
372 shared_lock(shared_lock const&) = delete;
373 shared_lock& operator=(shared_lock const&) = delete;
375 _LIBCPP_INLINE_VISIBILITY
376 shared_lock(shared_lock&& __u) _NOEXCEPT
384 _LIBCPP_INLINE_VISIBILITY
385 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
388 __m_->unlock_shared();
392 __owns_ = __u.__owns_;
400 template <class Rep, class Period>
401 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
402 template <class Clock, class Duration>
403 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
407 _LIBCPP_INLINE_VISIBILITY
408 void swap(shared_lock& __u) _NOEXCEPT
410 _VSTD::swap(__m_, __u.__m_);
411 _VSTD::swap(__owns_, __u.__owns_);
414 _LIBCPP_INLINE_VISIBILITY
415 mutex_type* release() _NOEXCEPT
417 mutex_type* __m = __m_;
424 _LIBCPP_INLINE_VISIBILITY
425 bool owns_lock() const _NOEXCEPT {return __owns_;}
427 _LIBCPP_INLINE_VISIBILITY
428 explicit operator bool () const _NOEXCEPT {return __owns_;}
430 _LIBCPP_INLINE_VISIBILITY
431 mutex_type* mutex() const _NOEXCEPT {return __m_;}
434 template <class _Mutex>
436 shared_lock<_Mutex>::lock()
439 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
441 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
446 template <class _Mutex>
448 shared_lock<_Mutex>::try_lock()
451 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
453 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
454 __owns_ = __m_->try_lock_shared();
458 template <class _Mutex>
459 template <class _Rep, class _Period>
461 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
464 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
466 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
467 __owns_ = __m_->try_lock_shared_for(__d);
471 template <class _Mutex>
472 template <class _Clock, class _Duration>
474 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
477 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
479 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
480 __owns_ = __m_->try_lock_shared_until(__t);
484 template <class _Mutex>
486 shared_lock<_Mutex>::unlock()
489 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
490 __m_->unlock_shared();
494 template <class _Mutex>
495 inline _LIBCPP_INLINE_VISIBILITY
497 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
500 _LIBCPP_END_NAMESPACE_STD
502 #endif // !_LIBCPP_HAS_NO_THREADS
504 #endif // _LIBCPP_STD_VER > 11
508 #endif // _LIBCPP_SHARED_MUTEX