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 
46 namespace 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 
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
247  { __x.swap(__y); }
248 
249 _GLIBCXX_END_NAMESPACE_VERSION
250 } // namespace
251 
252 #endif // C++11
253 #endif // _GLIBCXX_UNIQUE_LOCK_H
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:52
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
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.
Definition: unique_lock.h:246