1 // <shared_mutex> -*- C++ -*-
3 // Copyright (C) 2013-2014 Free Software Foundation, Inc.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file include/shared_mutex
26 * This is a Standard C++ Library header.
29 #ifndef _GLIBCXX_SHARED_MUTEX
30 #define _GLIBCXX_SHARED_MUTEX 1
32 #pragma GCC system_header
34 #if __cplusplus <= 201103L
35 # include <bits/c++14_warning.h>
38 #include <bits/c++config.h>
40 #include <condition_variable>
41 #include <bits/functexcept.h>
43 namespace std _GLIBCXX_VISIBILITY(default)
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
52 #ifdef _GLIBCXX_USE_C99_STDINT_TR1
53 #ifdef _GLIBCXX_HAS_GTHREADS
55 #define __cpp_lib_shared_timed_mutex 201402
57 /// shared_timed_mutex
58 class shared_timed_mutex
60 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
61 struct _Mutex : mutex, __timed_mutex_impl<_Mutex>
63 template<typename _Rep, typename _Period>
65 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
66 { return _M_try_lock_for(__rtime); }
68 template<typename _Clock, typename _Duration>
70 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
71 { return _M_try_lock_until(__atime); }
77 // Based on Howard Hinnant's reference implementation from N2406
80 condition_variable _M_gate1;
81 condition_variable _M_gate2;
84 static constexpr unsigned _S_write_entered
85 = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
86 static constexpr unsigned _M_n_readers = ~_S_write_entered;
89 shared_timed_mutex() : _M_state(0) {}
93 _GLIBCXX_DEBUG_ASSERT( _M_state == 0 );
96 shared_timed_mutex(const shared_timed_mutex&) = delete;
97 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
99 // Exclusive ownership
104 unique_lock<mutex> __lk(_M_mut);
105 while (_M_state & _S_write_entered)
107 _M_state |= _S_write_entered;
108 while (_M_state & _M_n_readers)
115 unique_lock<mutex> __lk(_M_mut, try_to_lock);
116 if (__lk.owns_lock() && _M_state == 0)
118 _M_state = _S_write_entered;
124 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
125 template<typename _Rep, typename _Period>
127 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
129 unique_lock<_Mutex> __lk(_M_mut, __rel_time);
130 if (__lk.owns_lock() && _M_state == 0)
132 _M_state = _S_write_entered;
138 template<typename _Clock, typename _Duration>
140 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
142 unique_lock<_Mutex> __lk(_M_mut, __abs_time);
143 if (__lk.owns_lock() && _M_state == 0)
145 _M_state = _S_write_entered;
156 lock_guard<_Mutex> __lk(_M_mut);
159 _M_gate1.notify_all();
167 unique_lock<mutex> __lk(_M_mut);
168 while ((_M_state & _S_write_entered)
169 || (_M_state & _M_n_readers) == _M_n_readers)
173 unsigned __num_readers = (_M_state & _M_n_readers) + 1;
174 _M_state &= ~_M_n_readers;
175 _M_state |= __num_readers;
181 unique_lock<_Mutex> __lk(_M_mut, try_to_lock);
182 unsigned __num_readers = _M_state & _M_n_readers;
183 if (__lk.owns_lock() && !(_M_state & _S_write_entered)
184 && __num_readers != _M_n_readers)
187 _M_state &= ~_M_n_readers;
188 _M_state |= __num_readers;
194 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
195 template<typename _Rep, typename _Period>
197 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
199 unique_lock<_Mutex> __lk(_M_mut, __rel_time);
200 if (__lk.owns_lock())
202 unsigned __num_readers = _M_state & _M_n_readers;
203 if (!(_M_state & _S_write_entered)
204 && __num_readers != _M_n_readers)
207 _M_state &= ~_M_n_readers;
208 _M_state |= __num_readers;
215 template <typename _Clock, typename _Duration>
217 try_lock_shared_until(const chrono::time_point<_Clock,
218 _Duration>& __abs_time)
220 unique_lock<_Mutex> __lk(_M_mut, __abs_time);
221 if (__lk.owns_lock())
223 unsigned __num_readers = _M_state & _M_n_readers;
224 if (!(_M_state & _S_write_entered)
225 && __num_readers != _M_n_readers)
228 _M_state &= ~_M_n_readers;
229 _M_state |= __num_readers;
240 lock_guard<_Mutex> __lk(_M_mut);
241 unsigned __num_readers = (_M_state & _M_n_readers) - 1;
242 _M_state &= ~_M_n_readers;
243 _M_state |= __num_readers;
244 if (_M_state & _S_write_entered)
246 if (__num_readers == 0)
247 _M_gate2.notify_one();
251 if (__num_readers == _M_n_readers - 1)
252 _M_gate1.notify_one();
256 #endif // _GLIBCXX_HAS_GTHREADS
259 template<typename _Mutex>
263 typedef _Mutex mutex_type;
267 shared_lock() noexcept : _M_pm(nullptr), _M_owns(false) { }
270 shared_lock(mutex_type& __m) : _M_pm(&__m), _M_owns(true)
271 { __m.lock_shared(); }
273 shared_lock(mutex_type& __m, defer_lock_t) noexcept
274 : _M_pm(&__m), _M_owns(false) { }
276 shared_lock(mutex_type& __m, try_to_lock_t)
277 : _M_pm(&__m), _M_owns(__m.try_lock_shared()) { }
279 shared_lock(mutex_type& __m, adopt_lock_t)
280 : _M_pm(&__m), _M_owns(true) { }
282 template<typename _Clock, typename _Duration>
283 shared_lock(mutex_type& __m,
284 const chrono::time_point<_Clock, _Duration>& __abs_time)
285 : _M_pm(&__m), _M_owns(__m.try_lock_shared_until(__abs_time)) { }
287 template<typename _Rep, typename _Period>
288 shared_lock(mutex_type& __m,
289 const chrono::duration<_Rep, _Period>& __rel_time)
290 : _M_pm(&__m), _M_owns(__m.try_lock_shared_for(__rel_time)) { }
295 _M_pm->unlock_shared();
298 shared_lock(shared_lock const&) = delete;
299 shared_lock& operator=(shared_lock const&) = delete;
301 shared_lock(shared_lock&& __sl) noexcept : shared_lock()
305 operator=(shared_lock&& __sl) noexcept
307 shared_lock(std::move(__sl)).swap(*this);
315 _M_pm->lock_shared();
323 return _M_owns = _M_pm->try_lock_shared();
326 template<typename _Rep, typename _Period>
328 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
331 return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
334 template<typename _Clock, typename _Duration>
336 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
339 return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
346 __throw_system_error(int(errc::resource_deadlock_would_occur));
347 _M_pm->unlock_shared();
354 swap(shared_lock& __u) noexcept
356 std::swap(_M_pm, __u._M_pm);
357 std::swap(_M_owns, __u._M_owns);
364 return std::exchange(_M_pm, nullptr);
369 bool owns_lock() const noexcept { return _M_owns; }
371 explicit operator bool() const noexcept { return _M_owns; }
373 mutex_type* mutex() const noexcept { return _M_pm; }
379 if (_M_pm == nullptr)
380 __throw_system_error(int(errc::operation_not_permitted));
382 __throw_system_error(int(errc::resource_deadlock_would_occur));
389 /// Swap specialization for shared_lock
390 template<typename _Mutex>
392 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
395 #endif // _GLIBCXX_USE_C99_STDINT_TR1
398 _GLIBCXX_END_NAMESPACE_VERSION
403 #endif // _GLIBCXX_SHARED_MUTEX