tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
unique_lock.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2019 Tobias Hienzsch
3
4#ifndef TETL_MUTEX_UNIQUE_LOCK_HPP
5#define TETL_MUTEX_UNIQUE_LOCK_HPP
6
7#include <etl/_chrono/duration.hpp>
8#include <etl/_chrono/time_point.hpp>
9#include <etl/_mutex/tags.hpp>
10#include <etl/_utility/exchange.hpp>
11#include <etl/_utility/swap.hpp>
12
13namespace etl {
14
15/// \brief The struct unique_lock is a general-purpose mutex ownership wrapper
16/// allowing deferred locking, time-constrained attempts at locking, recursive
17/// locking, transfer of lock ownership, and use with condition variables.
18///
19/// \details The struct unique_lock is movable, but not copyable -- it meets the
20/// requirements of MoveConstructible and MoveAssignable but not of
21/// CopyConstructible or CopyAssignable. The struct unique_lock meets the
22/// BasicLockable requirements. If Mutex meets the Lockable requirements,
23/// unique_lock also meets the Lockable requirements (ex.: can be used in lock);
24/// if Mutex meets the TimedLockable requirements, unique_lock also meets the
25/// TimedLockable requirements.
26///
27/// \ingroup mutex
28template <typename Mutex>
30private:
31 Mutex* _mutex{nullptr};
32 bool _owns{false};
33
34public:
35 using mutex_type = Mutex;
36
37 /// \brief Constructs a unique_lock with no associated mutex.
38 constexpr unique_lock() noexcept = default;
39
40 /// \brief Constructs a unique_lock with m as the associated mutex.
41 /// Additionally: Locks the associated mutex by calling m.lock(). The
42 /// behavior is undefined if the current thread already owns the mutex
43 /// except when the mutex is recursive.
44 explicit constexpr unique_lock(mutex_type& m)
45 : _mutex{&m}
46 {
47 lock();
48 }
49
50 /// \brief Constructs a unique_lock with m as the associated mutex.
51 /// Additionally: Does not lock the associated mutex.
52 constexpr unique_lock(mutex_type& m, defer_lock_t /*tag*/) noexcept
53 : _mutex{&m}
54 {
55 }
56
57 /// \brief Constructs a unique_lock with m as the associated mutex.
58 /// Additionally: Tries to lock the associated mutex without blocking by
59 /// calling m.try_lock(). The behavior is undefined if the current thread
60 /// already owns the mutex except when the mutex is recursive.
61 constexpr unique_lock(mutex_type& m, try_to_lock_t /*tag*/) noexcept
62 : _mutex{&m}
63 {
65 }
66
67 /// \brief Constructs a unique_lock with m as the associated mutex.
68 /// Additionally: Assumes the calling thread already owns m.
69 constexpr unique_lock(mutex_type& m, adopt_lock_t /*tag*/)
70 : _mutex{&m}
71 , _owns{true}
72 {
73 }
74
75 /// \brief Constructs a unique_lock with m as the associated mutex.
76 /// Additionally: Tries to lock the associated mutex by calling
77 /// m.try_lock_until(timeout_time). Blocks until specified timeout_time has
78 /// been reached or the lock is acquired, whichever comes first. May block
79 /// for longer than until timeout_time has been reached.
80 template <typename Clock, typename Duration>
81 constexpr unique_lock(mutex_type& m, chrono::time_point<Clock, Duration> const& absTime) noexcept
82 : _mutex{&m}
83 {
84 try_lock_until(absTime);
85 }
86
87 /// \brief Constructs a unique_lock with m as the associated mutex.
88 /// Additionally: Tries to lock the associated mutex by calling
89 /// m.try_lock_for(timeout_duration). Blocks until specified
90 /// timeout_duration has elapsed or the lock is acquired, whichever comes
91 /// first. May block for longer than timeout_duration.
92 template <typename Rep, typename Period>
93 constexpr unique_lock(mutex_type& m, chrono::duration<Rep, Period> const& relTime) noexcept
94 : _mutex{&m}
95 {
96 try_lock_for(relTime);
97 }
98
99 /// \brief Deleted copy constructor. unique_lock is move only.
100 constexpr unique_lock(unique_lock const&) = delete;
101
102 /// \brief Deleted copy assignment. unique_lock is move only.
103 constexpr auto operator=(unique_lock const&) -> unique_lock& = delete;
104
105 /// \brief Move constructor. Initializes the unique_lock with the contents
106 /// of other. Leaves other with no associated mutex.
107 constexpr unique_lock(unique_lock&& u) noexcept
108 : _mutex{exchange(u._mutex, nullptr)}
109 , _owns{exchange(u._owns, false)}
110 {
111 }
112
113 /// \brief Move assignment operator. Replaces the contents with those of
114 /// other using move semantics. If prior to the call *this has an associated
115 /// mutex and has acquired ownership of it, the mutex is unlocked.
116 constexpr auto operator=(unique_lock&& u) noexcept -> unique_lock&
117 {
118 if (_mutex != nullptr && _owns) {
119 unlock();
120 }
121 _mutex = exchange(u._mutex, nullptr);
122 _owns = exchange(u._owns, false);
123 return *this;
124 }
125
126 constexpr ~unique_lock() noexcept
127 {
128 unlock();
129 }
130
131 /// \brief Locks (i.e., takes ownership of) the associated mutex.
132 constexpr auto lock() noexcept(noexcept(_mutex->lock())) -> void
133 {
134 if ((_mutex != nullptr) and !_owns) {
135 _mutex->lock();
136 _owns = true;
137 }
138 }
139
140 /// \brief Tries to lock (i.e., takes ownership of) the associated mutex
141 /// without blocking.
142 /// \returns true if the ownership of the mutex has been acquired
143 /// successfully, false otherwise.
144 constexpr auto try_lock() noexcept(noexcept(_mutex->try_lock())) -> bool
145 {
146 if ((_mutex != nullptr) && !_owns) {
147 if (auto success = _mutex->try_lock(); success) {
148 _owns = true;
149 return true;
150 }
151 }
152
153 return false;
154 }
155
156 /// \brief Tries to lock (i.e., takes ownership of) the associated mutex.
157 /// Blocks until specified timeout_duration has elapsed or the lock is
158 /// acquired, whichever comes first. On successful lock acquisition returns
159 /// true, otherwise returns false. Effectively calls
160 /// mutex()->try_lock_for(timeout_duration). This function may block for
161 /// longer than timeout_duration due to scheduling or resource contention
162 /// delays.
163 template <typename Rep, typename Period>
164 constexpr auto try_lock_for(chrono::duration<Rep, Period> const& dur) noexcept(noexcept(_mutex->try_lock_for(dur)))
165 -> bool
166 {
167 if ((_mutex != nullptr) && !_owns) {
168 if (auto success = _mutex->try_lock_for(dur); success) {
169 _owns = true;
170 return true;
171 }
172 }
173 return false;
174 }
175
176 /// \brief Tries to lock (i.e., takes ownership of) the associated mutex
177 /// without blocking.
178 template <typename Clock, typename Duration>
179 constexpr auto
180 try_lock_until(chrono::time_point<Clock, Duration> const& tp) noexcept(noexcept(_mutex->try_lock_until(tp))) -> bool
181 {
182 if ((_mutex != nullptr) && !_owns) {
183 if (auto success = _mutex->try_lock_until(tp); success) {
184 _owns = true;
185 return true;
186 }
187 }
188 return false;
189 }
190
191 /// \brief Unlocks (i.e., releases ownership of) the associated mutex and
192 /// releases ownership. Silently does nothing, if there is no associated
193 /// mutex or if the mutex is not locked.
194 constexpr auto unlock() -> void
195 {
196 if ((_mutex != nullptr) and _owns) {
197 _mutex->unlock();
198 _owns = false;
199 }
200 }
201
202 /// \brief Exchanges the internal states of the lock objects.
203 constexpr auto swap(unique_lock& other) noexcept -> void
204 {
205 using etl::swap;
206 swap(_mutex, other._mutex);
207 swap(_owns, other._owns);
208 }
209
210 /// \brief Breaks the association of the associated mutex, if any, and
211 /// *this. No locks are unlocked. If the *this held ownership of the
212 /// associated mutex prior to the call, the caller is now responsible to
213 /// unlock the mutex.
214 ///
215 /// \returns Pointer to the associated mutex or a null pointer if there was
216 /// no associated mutex.
217 [[nodiscard]] constexpr auto release() noexcept -> mutex_type*
218 {
219 _owns = false;
220 return _mutex;
221 }
222
223 /// \brief Checks whether *this owns a locked mutex or not.
224 [[nodiscard]] constexpr auto owns_lock() const noexcept -> bool
225 {
226 return _owns;
227 }
228
229 /// \brief Checks whether *this owns a locked mutex or not.
230 [[nodiscard]] explicit constexpr operator bool() const noexcept
231 {
232 return owns_lock();
233 }
234
235 /// \brief Returns a pointer to the associated mutex, or a null pointer if
236 /// there is no associated mutex.
237 [[nodiscard]] constexpr auto mutex() const noexcept -> mutex_type*
238 {
239 return _mutex;
240 }
241
242 /// \brief Specializes the swap algorithm for unique_lock. Exchanges the state of lhs with that of rhs.
243 friend constexpr auto swap(unique_lock& lhs, unique_lock& rhs) noexcept(noexcept(lhs.swap(rhs))) -> void
244 {
245 lhs.swap(rhs);
246 }
247};
248
249} // namespace etl
250
251#endif // TETL_MUTEX_UNIQUE_LOCK_HPP
Definition abs.hpp:12
Definition adjacent_find.hpp:9
Empty struct tag types used to specify locking strategy for etl::lock_guard, etl::scoped_lock,...
Definition tags.hpp:42
Class template etl::chrono::duration represents a time interval.
Definition duration.hpp:32
Class template time_point represents a point in time. It is implemented as if it stores a value of ty...
Definition time_point.hpp:22
Empty struct tag types used to specify locking strategy for etl::lock_guard, etl::scoped_lock,...
Definition tags.hpp:14
Empty struct tag types used to specify locking strategy for etl::lock_guard, etl::scoped_lock,...
Definition tags.hpp:28
The struct unique_lock is a general-purpose mutex ownership wrapper allowing deferred locking,...
Definition unique_lock.hpp:29
constexpr unique_lock(unique_lock const &)=delete
Deleted copy constructor. unique_lock is move only.
constexpr unique_lock(mutex_type &m, adopt_lock_t)
Constructs a unique_lock with m as the associated mutex. Additionally: Assumes the calling thread alr...
Definition unique_lock.hpp:69
constexpr auto mutex() const noexcept -> mutex_type *
Returns a pointer to the associated mutex, or a null pointer if there is no associated mutex.
Definition unique_lock.hpp:237
constexpr auto swap(unique_lock &other) noexcept -> void
Exchanges the internal states of the lock objects.
Definition unique_lock.hpp:203
constexpr auto owns_lock() const noexcept -> bool
Checks whether *this owns a locked mutex or not.
Definition unique_lock.hpp:224
constexpr auto operator=(unique_lock &&u) noexcept -> unique_lock &
Move assignment operator. Replaces the contents with those of other using move semantics....
Definition unique_lock.hpp:116
constexpr auto try_lock_until(chrono::time_point< Clock, Duration > const &tp) noexcept(noexcept(_mutex->try_lock_until(tp))) -> bool
Tries to lock (i.e., takes ownership of) the associated mutex without blocking.
Definition unique_lock.hpp:180
constexpr auto operator=(unique_lock const &) -> unique_lock &=delete
Deleted copy assignment. unique_lock is move only.
constexpr auto release() noexcept -> mutex_type *
Breaks the association of the associated mutex, if any, and *this. No locks are unlocked....
Definition unique_lock.hpp:217
constexpr operator bool() const noexcept
Checks whether *this owns a locked mutex or not.
Definition unique_lock.hpp:230
constexpr auto lock() noexcept(noexcept(_mutex->lock())) -> void
Locks (i.e., takes ownership of) the associated mutex.
Definition unique_lock.hpp:132
constexpr auto unlock() -> void
Unlocks (i.e., releases ownership of) the associated mutex and releases ownership....
Definition unique_lock.hpp:194
constexpr unique_lock(mutex_type &m, chrono::time_point< Clock, Duration > const &absTime) noexcept
Constructs a unique_lock with m as the associated mutex. Additionally: Tries to lock the associated m...
Definition unique_lock.hpp:81
constexpr unique_lock(mutex_type &m, defer_lock_t) noexcept
Constructs a unique_lock with m as the associated mutex. Additionally: Does not lock the associated m...
Definition unique_lock.hpp:52
constexpr auto try_lock_for(chrono::duration< Rep, Period > const &dur) noexcept(noexcept(_mutex->try_lock_for(dur))) -> bool
Tries to lock (i.e., takes ownership of) the associated mutex. Blocks until specified timeout_duratio...
Definition unique_lock.hpp:164
constexpr ~unique_lock() noexcept
Definition unique_lock.hpp:126
friend constexpr auto swap(unique_lock &lhs, unique_lock &rhs) noexcept(noexcept(lhs.swap(rhs))) -> void
Specializes the swap algorithm for unique_lock. Exchanges the state of lhs with that of rhs.
Definition unique_lock.hpp:243
constexpr auto try_lock() noexcept(noexcept(_mutex->try_lock())) -> bool
Tries to lock (i.e., takes ownership of) the associated mutex without blocking.
Definition unique_lock.hpp:144
constexpr unique_lock(mutex_type &m, try_to_lock_t) noexcept
Constructs a unique_lock with m as the associated mutex. Additionally: Tries to lock the associated m...
Definition unique_lock.hpp:61
constexpr unique_lock() noexcept=default
Constructs a unique_lock with no associated mutex.
constexpr unique_lock(mutex_type &m, chrono::duration< Rep, Period > const &relTime) noexcept
Constructs a unique_lock with m as the associated mutex. Additionally: Tries to lock the associated m...
Definition unique_lock.hpp:93
constexpr unique_lock(mutex_type &m)
Constructs a unique_lock with m as the associated mutex. Additionally: Locks the associated mutex by ...
Definition unique_lock.hpp:44
constexpr unique_lock(unique_lock &&u) noexcept
Move constructor. Initializes the unique_lock with the contents of other. Leaves other with no associ...
Definition unique_lock.hpp:107