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>
39 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
41 # include <condition_variable>
43 #include <bits/functexcept.h>
45 namespace std _GLIBCXX_VISIBILITY(default)
47 _GLIBCXX_BEGIN_NAMESPACE_VERSION
54 #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)
56 #define __cpp_lib_shared_timed_mutex 201402
58 /// shared_timed_mutex
59 class shared_timed_mutex
61 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
62 struct _Mutex : mutex, __timed_mutex_impl<_Mutex>
64 template<typename _Rep, typename _Period>
66 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
67 { return _M_try_lock_for(__rtime); }
69 template<typename _Clock, typename _Duration>
71 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
72 { return _M_try_lock_until(__atime); }
78 // Based on Howard Hinnant's reference implementation from N2406
81 condition_variable _M_gate1;
82 condition_variable _M_gate2;
85 static constexpr unsigned _S_write_entered
86 = 1U << (sizeof(unsigned)*__CHAR_BIT__ - 1);
87 static constexpr unsigned _M_n_readers = ~_S_write_entered;
90 shared_timed_mutex() : _M_state(0) {}
94 _GLIBCXX_DEBUG_ASSERT( _M_state == 0 );
97 shared_timed_mutex(const shared_timed_mutex&) = delete;
98 shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
100 // Exclusive ownership
105 unique_lock<mutex> __lk(_M_mut);
106 while (_M_state & _S_write_entered)
108 _M_state |= _S_write_entered;
109 while (_M_state & _M_n_readers)
116 unique_lock<mutex> __lk(_M_mut, try_to_lock);
117 if (__lk.owns_lock() && _M_state == 0)
119 _M_state = _S_write_entered;
125 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
126 template<typename _Rep, typename _Period>
128 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
130 unique_lock<_Mutex> __lk(_M_mut, __rel_time);
131 if (__lk.owns_lock() && _M_state == 0)
133 _M_state = _S_write_entered;
139 template<typename _Clock, typename _Duration>
141 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
143 unique_lock<_Mutex> __lk(_M_mut, __abs_time);
144 if (__lk.owns_lock() && _M_state == 0)
146 _M_state = _S_write_entered;
157 lock_guard<_Mutex> __lk(_M_mut);
160 _M_gate1.notify_all();
168 unique_lock<mutex> __lk(_M_mut);
169 while ((_M_state & _S_write_entered)
170 || (_M_state & _M_n_readers) == _M_n_readers)
174 unsigned __num_readers = (_M_state & _M_n_readers) + 1;
175 _M_state &= ~_M_n_readers;
176 _M_state |= __num_readers;
182 unique_lock<_Mutex> __lk(_M_mut, try_to_lock);
183 unsigned __num_readers = _M_state & _M_n_readers;
184 if (__lk.owns_lock() && !(_M_state & _S_write_entered)
185 && __num_readers != _M_n_readers)
188 _M_state &= ~_M_n_readers;
189 _M_state |= __num_readers;
195 #if _GTHREAD_USE_MUTEX_TIMEDLOCK
196 template<typename _Rep, typename _Period>
198 try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
200 unique_lock<_Mutex> __lk(_M_mut, __rel_time);
201 if (__lk.owns_lock())
203 unsigned __num_readers = _M_state & _M_n_readers;
204 if (!(_M_state & _S_write_entered)
205 && __num_readers != _M_n_readers)
208 _M_state &= ~_M_n_readers;
209 _M_state |= __num_readers;
216 template <typename _Clock, typename _Duration>
218 try_lock_shared_until(const chrono::time_point<_Clock,
219 _Duration>& __abs_time)
221 unique_lock<_Mutex> __lk(_M_mut, __abs_time);
222 if (__lk.owns_lock())
224 unsigned __num_readers = _M_state & _M_n_readers;
225 if (!(_M_state & _S_write_entered)
226 && __num_readers != _M_n_readers)
229 _M_state &= ~_M_n_readers;
230 _M_state |= __num_readers;
241 lock_guard<_Mutex> __lk(_M_mut);
242 unsigned __num_readers = (_M_state & _M_n_readers) - 1;
243 _M_state &= ~_M_n_readers;
244 _M_state |= __num_readers;
245 if (_M_state & _S_write_entered)
247 if (__num_readers == 0)
248 _M_gate2.notify_one();
252 if (__num_readers == _M_n_readers - 1)
253 _M_gate1.notify_one();
257 #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1
260 template<typename _Mutex>
264 typedef _Mutex mutex_type;
268 shared_lock() noexcept : _M_pm(nullptr), _M_owns(false) { }
271 shared_lock(mutex_type& __m) : _M_pm(&__m), _M_owns(true)
272 { __m.lock_shared(); }
274 shared_lock(mutex_type& __m, defer_lock_t) noexcept
275 : _M_pm(&__m), _M_owns(false) { }
277 shared_lock(mutex_type& __m, try_to_lock_t)
278 : _M_pm(&__m), _M_owns(__m.try_lock_shared()) { }
280 shared_lock(mutex_type& __m, adopt_lock_t)
281 : _M_pm(&__m), _M_owns(true) { }
283 template<typename _Clock, typename _Duration>
284 shared_lock(mutex_type& __m,
285 const chrono::time_point<_Clock, _Duration>& __abs_time)
286 : _M_pm(&__m), _M_owns(__m.try_lock_shared_until(__abs_time)) { }
288 template<typename _Rep, typename _Period>
289 shared_lock(mutex_type& __m,
290 const chrono::duration<_Rep, _Period>& __rel_time)
291 : _M_pm(&__m), _M_owns(__m.try_lock_shared_for(__rel_time)) { }
296 _M_pm->unlock_shared();
299 shared_lock(shared_lock const&) = delete;
300 shared_lock& operator=(shared_lock const&) = delete;
302 shared_lock(shared_lock&& __sl) noexcept : shared_lock()
306 operator=(shared_lock&& __sl) noexcept
308 shared_lock(std::move(__sl)).swap(*this);
316 _M_pm->lock_shared();
324 return _M_owns = _M_pm->try_lock_shared();
327 template<typename _Rep, typename _Period>
329 try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
332 return _M_owns = _M_pm->try_lock_shared_for(__rel_time);
335 template<typename _Clock, typename _Duration>
337 try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
340 return _M_owns = _M_pm->try_lock_shared_until(__abs_time);
347 __throw_system_error(int(errc::resource_deadlock_would_occur));
348 _M_pm->unlock_shared();
355 swap(shared_lock& __u) noexcept
357 std::swap(_M_pm, __u._M_pm);
358 std::swap(_M_owns, __u._M_owns);
365 return std::exchange(_M_pm, nullptr);
370 bool owns_lock() const noexcept { return _M_owns; }
372 explicit operator bool() const noexcept { return _M_owns; }
374 mutex_type* mutex() const noexcept { return _M_pm; }
380 if (_M_pm == nullptr)
381 __throw_system_error(int(errc::operation_not_permitted));
383 __throw_system_error(int(errc::resource_deadlock_would_occur));
390 /// Swap specialization for shared_lock
391 template<typename _Mutex>
393 swap(shared_lock<_Mutex>& __x, shared_lock<_Mutex>& __y) noexcept
397 _GLIBCXX_END_NAMESPACE_VERSION
402 #endif // _GLIBCXX_SHARED_MUTEX