libstdc++
unique_lock.h
Go to the documentation of this file.
1// std::unique_lock implementation -*- C++ -*-
2
3// Copyright (C) 2008-2025 Free Software Foundation, Inc.
4//
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)
9// any later version.
10
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.
15
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.
19
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/>.
24
25/** @file bits/unique_lock.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{mutex}
28 */
29
30#ifndef _GLIBCXX_UNIQUE_LOCK_H
31#define _GLIBCXX_UNIQUE_LOCK_H 1
32
33#ifdef _GLIBCXX_SYSHDR
34#pragma GCC system_header
35#endif
36
37#if __cplusplus < 201103L
38# include <bits/c++0x_warning.h>
39#else
40
41#include <bits/chrono.h>
42#include <bits/error_constants.h> // for std::errc
43#include <bits/move.h> // for std::swap
44#include <bits/std_mutex.h> // for std::defer_lock_t
45
46namespace std _GLIBCXX_VISIBILITY(default)
47{
48_GLIBCXX_BEGIN_NAMESPACE_VERSION
49
50 /** @brief A movable scoped lock type.
51 *
52 * A unique_lock controls mutex ownership within a scope. Ownership of the
53 * mutex can be delayed until after construction and can be transferred
54 * to another unique_lock by move construction or move assignment. If a
55 * mutex lock is owned when the destructor runs ownership will be released.
56 *
57 * @headerfile mutex
58 * @ingroup mutexes
59 * @since C++11
60 */
61 template<typename _Mutex>
62 class unique_lock
63 {
64 public:
65 typedef _Mutex mutex_type;
66
67 unique_lock() noexcept
68 : _M_device(0), _M_owns(false)
69 { }
70
71 [[__nodiscard__]]
72 explicit unique_lock(mutex_type& __m)
73 : _M_device(std::__addressof(__m)), _M_owns(false)
74 {
75 lock();
76 _M_owns = true;
77 }
78
79 unique_lock(mutex_type& __m, defer_lock_t) noexcept
80 : _M_device(std::__addressof(__m)), _M_owns(false)
81 { }
82
83 [[__nodiscard__]]
84 unique_lock(mutex_type& __m, try_to_lock_t)
85 : _M_device(std::__addressof(__m)), _M_owns(_M_device->try_lock())
86 { }
87
88 [[__nodiscard__]]
89 unique_lock(mutex_type& __m, adopt_lock_t) noexcept
90 : _M_device(std::__addressof(__m)), _M_owns(true)
91 {
92 // XXX calling thread owns mutex
93 }
94
95 template<typename _Clock, typename _Duration>
96 [[__nodiscard__]]
97 unique_lock(mutex_type& __m,
99 : _M_device(std::__addressof(__m)),
100 _M_owns(_M_device->try_lock_until(__atime))
101 { }
102
103 template<typename _Rep, typename _Period>
104 [[__nodiscard__]]
105 unique_lock(mutex_type& __m,
106 const chrono::duration<_Rep, _Period>& __rtime)
107 : _M_device(std::__addressof(__m)),
108 _M_owns(_M_device->try_lock_for(__rtime))
109 { }
110
111 ~unique_lock()
112 {
113 if (_M_owns)
114 unlock();
115 }
116
117 unique_lock(const unique_lock&) = delete;
118 unique_lock& operator=(const unique_lock&) = delete;
119
120 unique_lock(unique_lock&& __u) noexcept
121 : _M_device(__u._M_device), _M_owns(__u._M_owns)
122 {
123 __u._M_device = 0;
124 __u._M_owns = false;
125 }
126
127 unique_lock& operator=(unique_lock&& __u) noexcept
128 {
129 // _GLIBCXX_RESOLVE_LIB_DEFECTS
130 // 4172. unique_lock self-move-assignment is broken
131 unique_lock(std::move(__u)).swap(*this);
132 return *this;
133 }
134
135 void
136 lock()
137 {
138 if (!_M_device)
139 __throw_system_error(int(errc::operation_not_permitted));
140 else if (_M_owns)
141 __throw_system_error(int(errc::resource_deadlock_would_occur));
142 else
143 {
144 _M_device->lock();
145 _M_owns = true;
146 }
147 }
148
149 _GLIBCXX_NODISCARD
150 bool
151 try_lock()
152 {
153 if (!_M_device)
154 __throw_system_error(int(errc::operation_not_permitted));
155 else if (_M_owns)
156 __throw_system_error(int(errc::resource_deadlock_would_occur));
157 else
158 {
159 _M_owns = _M_device->try_lock();
160 return _M_owns;
161 }
162 }
163
164 template<typename _Clock, typename _Duration>
165 _GLIBCXX_NODISCARD
166 bool
167 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
168 {
169 if (!_M_device)
170 __throw_system_error(int(errc::operation_not_permitted));
171 else if (_M_owns)
172 __throw_system_error(int(errc::resource_deadlock_would_occur));
173 else
174 {
175 _M_owns = _M_device->try_lock_until(__atime);
176 return _M_owns;
177 }
178 }
179
180 template<typename _Rep, typename _Period>
181 _GLIBCXX_NODISCARD
182 bool
183 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
184 {
185 if (!_M_device)
186 __throw_system_error(int(errc::operation_not_permitted));
187 else if (_M_owns)
188 __throw_system_error(int(errc::resource_deadlock_would_occur));
189 else
190 {
191 _M_owns = _M_device->try_lock_for(__rtime);
192 return _M_owns;
193 }
194 }
195
196 void
197 unlock()
198 {
199 if (!_M_owns)
200 __throw_system_error(int(errc::operation_not_permitted));
201 else if (_M_device)
202 {
203 _M_device->unlock();
204 _M_owns = false;
205 }
206 }
207
208 void
209 swap(unique_lock& __u) noexcept
210 {
211 std::swap(_M_device, __u._M_device);
212 std::swap(_M_owns, __u._M_owns);
213 }
214
215 mutex_type*
216 release() noexcept
217 {
218 mutex_type* __ret = _M_device;
219 _M_device = 0;
220 _M_owns = false;
221 return __ret;
222 }
223
224 _GLIBCXX_NODISCARD
225 bool
226 owns_lock() const noexcept
227 { return _M_owns; }
228
229 explicit operator bool() const noexcept
230 { return owns_lock(); }
231
232 _GLIBCXX_NODISCARD
233 mutex_type*
234 mutex() const noexcept
235 { return _M_device; }
236
237 private:
238 mutex_type* _M_device;
239 bool _M_owns;
240 };
241
242 /// Swap overload for unique_lock objects.
243 /// @relates unique_lock
244 template<typename _Mutex>
245 inline void
246 swap(unique_lock<_Mutex>& __x, unique_lock<_Mutex>& __y) noexcept
247 { __x.swap(__y); }
248
249_GLIBCXX_END_NAMESPACE_VERSION
250} // namespace
251
252#endif // C++11
253#endif // _GLIBCXX_UNIQUE_LOCK_H
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
ISO C++ entities toplevel namespace is std.
chrono::duration represents a distance between two points in time
Definition chrono.h:516
chrono::time_point represents a point in time as measured by a clock
Definition chrono.h:927
Do not acquire ownership of the mutex.
Definition std_mutex.h:218
Try to acquire ownership of the mutex without blocking.
Definition std_mutex.h:221
Assume the calling thread has already obtained mutex ownership and manage it.
Definition std_mutex.h:225
void swap(unique_lock< _Mutex > &__x, unique_lock< _Mutex > &__y) noexcept
Swap overload for unique_lock objects.