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;
128 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
130 #include <__mutex_base>
132 #include <__undef_min_max>
134 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
135 #pragma GCC system_header
138 #ifdef _LIBCPP_HAS_NO_THREADS
139 #error <shared_mutex> is not supported on this single threaded system
140 #else // !_LIBCPP_HAS_NO_THREADS
142 _LIBCPP_BEGIN_NAMESPACE_STD
144 struct _LIBCPP_TYPE_VIS __shared_mutex_base
147 condition_variable __gate1_;
148 condition_variable __gate2_;
151 static const unsigned __write_entered_ = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
152 static const unsigned __n_readers_ = ~__write_entered_;
154 __shared_mutex_base();
155 _LIBCPP_INLINE_VISIBILITY ~__shared_mutex_base() = default;
157 __shared_mutex_base(const __shared_mutex_base&) = delete;
158 __shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
160 // Exclusive ownership
161 void lock(); // blocking
166 void lock_shared(); // blocking
167 bool try_lock_shared();
168 void unlock_shared();
170 // typedef implementation-defined native_handle_type; // See 30.2.3
171 // native_handle_type native_handle(); // See 30.2.3
175 #if _LIBCPP_STD_VER > 14
176 class _LIBCPP_TYPE_VIS shared_mutex
178 __shared_mutex_base __base;
180 shared_mutex() : __base() {}
181 _LIBCPP_INLINE_VISIBILITY ~shared_mutex() = default;
183 shared_mutex(const shared_mutex&) = delete;
184 shared_mutex& operator=(const shared_mutex&) = delete;
186 // Exclusive ownership
187 _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); }
188 _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); }
189 _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); }
192 _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); }
193 _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); }
194 _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); }
196 // typedef __shared_mutex_base::native_handle_type native_handle_type;
197 // _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); }
202 class _LIBCPP_TYPE_VIS shared_timed_mutex
204 __shared_mutex_base __base;
206 shared_timed_mutex();
207 _LIBCPP_INLINE_VISIBILITY ~shared_timed_mutex() = default;
209 shared_timed_mutex(const shared_timed_mutex&) = delete;
210 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
212 // Exclusive ownership
215 template <class _Rep, class _Period>
216 _LIBCPP_INLINE_VISIBILITY
218 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
220 return try_lock_until(chrono::steady_clock::now() + __rel_time);
222 template <class _Clock, class _Duration>
223 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
225 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
230 bool try_lock_shared();
231 template <class _Rep, class _Period>
232 _LIBCPP_INLINE_VISIBILITY
234 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
236 return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
238 template <class _Clock, class _Duration>
239 _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
241 try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
242 void unlock_shared();
245 template <class _Clock, class _Duration>
247 shared_timed_mutex::try_lock_until(
248 const chrono::time_point<_Clock, _Duration>& __abs_time)
250 unique_lock<mutex> __lk(__base.__mut_);
251 if (__base.__state_ & __base.__write_entered_)
255 cv_status __status = __base.__gate1_.wait_until(__lk, __abs_time);
256 if ((__base.__state_ & __base.__write_entered_) == 0)
258 if (__status == cv_status::timeout)
262 __base.__state_ |= __base.__write_entered_;
263 if (__base.__state_ & __base.__n_readers_)
267 cv_status __status = __base.__gate2_.wait_until(__lk, __abs_time);
268 if ((__base.__state_ & __base.__n_readers_) == 0)
270 if (__status == cv_status::timeout)
272 __base.__state_ &= ~__base.__write_entered_;
273 __base.__gate1_.notify_all();
281 template <class _Clock, class _Duration>
283 shared_timed_mutex::try_lock_shared_until(
284 const chrono::time_point<_Clock, _Duration>& __abs_time)
286 unique_lock<mutex> __lk(__base.__mut_);
287 if ((__base.__state_ & __base.__write_entered_) || (__base.__state_ & __base.__n_readers_) == __base.__n_readers_)
291 cv_status status = __base.__gate1_.wait_until(__lk, __abs_time);
292 if ((__base.__state_ & __base.__write_entered_) == 0 &&
293 (__base.__state_ & __base.__n_readers_) < __base.__n_readers_)
295 if (status == cv_status::timeout)
299 unsigned __num_readers = (__base.__state_ & __base.__n_readers_) + 1;
300 __base.__state_ &= ~__base.__n_readers_;
301 __base.__state_ |= __num_readers;
305 template <class _Mutex>
309 typedef _Mutex mutex_type;
316 _LIBCPP_INLINE_VISIBILITY
317 shared_lock() _NOEXCEPT
322 _LIBCPP_INLINE_VISIBILITY
323 explicit shared_lock(mutex_type& __m)
324 : __m_(_VSTD::addressof(__m)),
326 {__m_->lock_shared();}
328 _LIBCPP_INLINE_VISIBILITY
329 shared_lock(mutex_type& __m, defer_lock_t) _NOEXCEPT
330 : __m_(_VSTD::addressof(__m)),
334 _LIBCPP_INLINE_VISIBILITY
335 shared_lock(mutex_type& __m, try_to_lock_t)
336 : __m_(_VSTD::addressof(__m)),
337 __owns_(__m.try_lock_shared())
340 _LIBCPP_INLINE_VISIBILITY
341 shared_lock(mutex_type& __m, adopt_lock_t)
342 : __m_(_VSTD::addressof(__m)),
346 template <class _Clock, class _Duration>
347 _LIBCPP_INLINE_VISIBILITY
348 shared_lock(mutex_type& __m,
349 const chrono::time_point<_Clock, _Duration>& __abs_time)
350 : __m_(_VSTD::addressof(__m)),
351 __owns_(__m.try_lock_shared_until(__abs_time))
354 template <class _Rep, class _Period>
355 _LIBCPP_INLINE_VISIBILITY
356 shared_lock(mutex_type& __m,
357 const chrono::duration<_Rep, _Period>& __rel_time)
358 : __m_(_VSTD::addressof(__m)),
359 __owns_(__m.try_lock_shared_for(__rel_time))
362 _LIBCPP_INLINE_VISIBILITY
366 __m_->unlock_shared();
369 shared_lock(shared_lock const&) = delete;
370 shared_lock& operator=(shared_lock const&) = delete;
372 _LIBCPP_INLINE_VISIBILITY
373 shared_lock(shared_lock&& __u) _NOEXCEPT
381 _LIBCPP_INLINE_VISIBILITY
382 shared_lock& operator=(shared_lock&& __u) _NOEXCEPT
385 __m_->unlock_shared();
389 __owns_ = __u.__owns_;
397 template <class Rep, class Period>
398 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
399 template <class Clock, class Duration>
400 bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
404 _LIBCPP_INLINE_VISIBILITY
405 void swap(shared_lock& __u) _NOEXCEPT
407 _VSTD::swap(__m_, __u.__m_);
408 _VSTD::swap(__owns_, __u.__owns_);
411 _LIBCPP_INLINE_VISIBILITY
412 mutex_type* release() _NOEXCEPT
414 mutex_type* __m = __m_;
421 _LIBCPP_INLINE_VISIBILITY
422 bool owns_lock() const _NOEXCEPT {return __owns_;}
424 _LIBCPP_INLINE_VISIBILITY
425 explicit operator bool () const _NOEXCEPT {return __owns_;}
427 _LIBCPP_INLINE_VISIBILITY
428 mutex_type* mutex() const _NOEXCEPT {return __m_;}
431 template <class _Mutex>
433 shared_lock<_Mutex>::lock()
436 __throw_system_error(EPERM, "shared_lock::lock: references null mutex");
438 __throw_system_error(EDEADLK, "shared_lock::lock: already locked");
443 template <class _Mutex>
445 shared_lock<_Mutex>::try_lock()
448 __throw_system_error(EPERM, "shared_lock::try_lock: references null mutex");
450 __throw_system_error(EDEADLK, "shared_lock::try_lock: already locked");
451 __owns_ = __m_->try_lock_shared();
455 template <class _Mutex>
456 template <class _Rep, class _Period>
458 shared_lock<_Mutex>::try_lock_for(const chrono::duration<_Rep, _Period>& __d)
461 __throw_system_error(EPERM, "shared_lock::try_lock_for: references null mutex");
463 __throw_system_error(EDEADLK, "shared_lock::try_lock_for: already locked");
464 __owns_ = __m_->try_lock_shared_for(__d);
468 template <class _Mutex>
469 template <class _Clock, class _Duration>
471 shared_lock<_Mutex>::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
474 __throw_system_error(EPERM, "shared_lock::try_lock_until: references null mutex");
476 __throw_system_error(EDEADLK, "shared_lock::try_lock_until: already locked");
477 __owns_ = __m_->try_lock_shared_until(__t);
481 template <class _Mutex>
483 shared_lock<_Mutex>::unlock()
486 __throw_system_error(EPERM, "shared_lock::unlock: not locked");
487 __m_->unlock_shared();
491 template <class _Mutex>
492 inline _LIBCPP_INLINE_VISIBILITY
494 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) _NOEXCEPT
497 _LIBCPP_END_NAMESPACE_STD
499 #endif // !_LIBCPP_HAS_NO_THREADS
501 #endif // _LIBCPP_STD_VER > 11
503 #endif // _LIBCPP_SHARED_MUTEX