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>
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
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 if(_M_owns)
130 unlock();
131
132 unique_lock(std::move(__u)).swap(*this);
133
134 __u._M_device = 0;
135 __u._M_owns = false;
136
137 return *this;
138 }
139
140 void
141 lock()
142 {
143 if (!_M_device)
144 __throw_system_error(int(errc::operation_not_permitted));
145 else if (_M_owns)
146 __throw_system_error(int(errc::resource_deadlock_would_occur));
147 else
148 {
149 _M_device->lock();
150 _M_owns = true;
151 }
152 }
153
154 _GLIBCXX_NODISCARD
155 bool
156 try_lock()
157 {
158 if (!_M_device)
159 __throw_system_error(int(errc::operation_not_permitted));
160 else if (_M_owns)
161 __throw_system_error(int(errc::resource_deadlock_would_occur));
162 else
163 {
164 _M_owns = _M_device->try_lock();
165 return _M_owns;
166 }
167 }
168
169 template<typename _Clock, typename _Duration>
170 _GLIBCXX_NODISCARD
171 bool
172 try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
173 {
174 if (!_M_device)
175 __throw_system_error(int(errc::operation_not_permitted));
176 else if (_M_owns)
177 __throw_system_error(int(errc::resource_deadlock_would_occur));
178 else
179 {
180 _M_owns = _M_device->try_lock_until(__atime);
181 return _M_owns;
182 }
183 }
184
185 template<typename _Rep, typename _Period>
186 _GLIBCXX_NODISCARD
187 bool
188 try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
189 {
190 if (!_M_device)
191 __throw_system_error(int(errc::operation_not_permitted));
192 else if (_M_owns)
193 __throw_system_error(int(errc::resource_deadlock_would_occur));
194 else
195 {
196 _M_owns = _M_device->try_lock_for(__rtime);
197 return _M_owns;
198 }
199 }
200
201 void
202 unlock()
203 {
204 if (!_M_owns)
205 __throw_system_error(int(errc::operation_not_permitted));
206 else if (_M_device)
207 {
208 _M_device->unlock();
209 _M_owns = false;
210 }
211 }
212
213 void
214 swap(unique_lock& __u) noexcept
215 {
216 std::swap(_M_device, __u._M_device);
217 std::swap(_M_owns, __u._M_owns);
218 }
219
220 mutex_type*
221 release() noexcept
222 {
223 mutex_type* __ret = _M_device;
224 _M_device = 0;
225 _M_owns = false;
226 return __ret;
227 }
228
229 _GLIBCXX_NODISCARD
230 bool
231 owns_lock() const noexcept
232 { return _M_owns; }
233
234 explicit operator bool() const noexcept
235 { return owns_lock(); }
236
237 _GLIBCXX_NODISCARD
238 mutex_type*
239 mutex() const noexcept
240 { return _M_device; }
241
242 private:
243 mutex_type* _M_device;
244 bool _M_owns;
245 };
246
247 /// Swap overload for unique_lock objects.
248 /// @relates unique_lock
249 template<typename _Mutex>
250 inline void
252 { __x.swap(__y); }
253
254_GLIBCXX_END_NAMESPACE_VERSION
255} // namespace
256
257#endif // C++11
258#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
A movable scoped lock type.
Definition unique_lock.h:63
void swap(unique_lock< _Mutex > &__x, unique_lock< _Mutex > &__y) noexcept
Swap overload for unique_lock objects.