Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qmutex.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QMUTEX_H
5#define QMUTEX_H
6
7#include <QtCore/qglobal.h>
8#include <QtCore/qatomic.h>
9#include <QtCore/qdeadlinetimer.h>
10#include <QtCore/qtsan_impl.h>
11
13
14#if QT_CONFIG(thread) || defined(Q_QDOC)
15
16#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) // these platforms use futex
17# define QT_MUTEX_LOCK_NOEXCEPT noexcept
18#else
19# define QT_MUTEX_LOCK_NOEXCEPT
20#endif
21
22class QMutex;
23class QRecursiveMutex;
24class QMutexPrivate;
25
26class Q_CORE_EXPORT QBasicMutex
27{
28 Q_DISABLE_COPY_MOVE(QBasicMutex)
29public:
30 constexpr QBasicMutex()
31 : d_ptr(nullptr)
32 {}
33
34 // BasicLockable concept
35 inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
36 QtTsan::mutexPreLock(this, 0u);
37
38 if (!fastTryLock())
39 lockInternal();
40
41 QtTsan::mutexPostLock(this, 0u, 0);
42 }
43
44 // BasicLockable concept
45 inline void unlock() noexcept {
46 Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked
47
48 QtTsan::mutexPreUnlock(this, 0u);
49
50 if (!fastTryUnlock())
51 unlockInternal();
52
54 }
55
56 bool tryLock() noexcept {
57 unsigned tsanFlags = QtTsan::TryLock;
58 QtTsan::mutexPreLock(this, tsanFlags);
59
60 const bool success = fastTryLock();
61
62 if (!success)
63 tsanFlags |= QtTsan::TryLockFailed;
64 QtTsan::mutexPostLock(this, tsanFlags, 0);
65
66 return success;
67 }
68
69 // Lockable concept
70 bool try_lock() noexcept { return tryLock(); }
71
72private:
73 inline bool fastTryLock() noexcept
74 {
75 if (d_ptr.loadRelaxed() != nullptr)
76 return false;
77 return d_ptr.testAndSetAcquire(nullptr, dummyLocked());
78 }
79 inline bool fastTryUnlock() noexcept {
80 return d_ptr.testAndSetRelease(dummyLocked(), nullptr);
81 }
82
83 void lockInternal() QT_MUTEX_LOCK_NOEXCEPT;
84 bool lockInternal(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT;
85#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
86 bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT;
87#endif
88 void unlockInternal() noexcept;
89 void destroyInternal(QMutexPrivate *d);
90
92 static inline QMutexPrivate *dummyLocked() {
93 return reinterpret_cast<QMutexPrivate *>(quintptr(1));
94 }
95
96 friend class QMutex;
97 friend class QMutexPrivate;
98};
99
100class Q_CORE_EXPORT QMutex : public QBasicMutex
101{
102public:
103 constexpr QMutex() = default;
104 ~QMutex()
105 {
106 QMutexPrivate *d = d_ptr.loadRelaxed();
107 if (d)
108 destroyInternal(d);
109 }
110
111#ifdef Q_QDOC
112 inline void lock() QT_MUTEX_LOCK_NOEXCEPT;
113 inline void unlock() noexcept;
114 bool tryLock() noexcept;
115#endif
116
117 // Lockable concept
118 bool try_lock() noexcept { return tryLock(); }
119
120
122 bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
123 {
125 }
126
127 bool tryLock(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT
128 {
129 unsigned tsanFlags = QtTsan::TryLock;
130 QtTsan::mutexPreLock(this, tsanFlags);
131
132 bool success = fastTryLock();
133
134 if (success) {
135 QtTsan::mutexPostLock(this, tsanFlags, 0);
136 return success;
137 }
138
139 success = lockInternal(timeout);
140
141 if (!success)
142 tsanFlags |= QtTsan::TryLockFailed;
143 QtTsan::mutexPostLock(this, tsanFlags, 0);
144
145 return success;
146 }
147
148 // TimedLockable concept
149 template <class Rep, class Period>
150 bool try_lock_for(std::chrono::duration<Rep, Period> duration)
151 {
152 return tryLock(QDeadlineTimer(duration));
153 }
154
155 // TimedLockable concept
156 template<class Clock, class Duration>
157 bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
158 {
159 return tryLock(QDeadlineTimer(timePoint));
160 }
161};
162
163class Q_CORE_EXPORT QRecursiveMutex
164{
165 Q_DISABLE_COPY_MOVE(QRecursiveMutex)
166 // written to by the thread that first owns 'mutex';
167 // read during attempts to acquire ownership of 'mutex' from any other thread:
168 QAtomicPointer<void> owner = nullptr;
169 // only ever accessed from the thread that owns 'mutex':
170 uint count = 0;
172
173public:
174 constexpr QRecursiveMutex() = default;
176
177
178 // BasicLockable concept
179 void lock() QT_MUTEX_LOCK_NOEXCEPT
181 QT_CORE_INLINE_SINCE(6, 6)
182 bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT;
183 bool tryLock(QDeadlineTimer timer) QT_MUTEX_LOCK_NOEXCEPT;
184 // BasicLockable concept
185 void unlock() noexcept;
186
187 // Lockable concept
188 bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); }
189
190 // TimedLockable concept
191 template <class Rep, class Period>
192 bool try_lock_for(std::chrono::duration<Rep, Period> duration)
193 {
194 return tryLock(QDeadlineTimer(duration));
195 }
196
197 // TimedLockable concept
198 template<class Clock, class Duration>
199 bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
200 {
201 return tryLock(QDeadlineTimer(timePoint));
202 }
203
204#ifndef Q_QDOC
205 // because tryLock(QDeadlineTimer::Forever) is tryLock(0)
206 bool tryLock(QDeadlineTimer::ForeverConstant) QT_MUTEX_LOCK_NOEXCEPT
207 { lock(); return true; }
208#endif
209};
210
211#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
212bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
213{
215}
216#endif
217
218template <typename Mutex>
219class QMutexLocker
220{
221public:
223 inline explicit QMutexLocker(Mutex *mutex) QT_MUTEX_LOCK_NOEXCEPT
224 {
225 m_mutex = mutex;
226 if (Q_LIKELY(mutex)) {
227 mutex->lock();
228 m_isLocked = true;
229 }
230 }
231
233 inline QMutexLocker(QMutexLocker &&other) noexcept
234 : m_mutex(std::exchange(other.m_mutex, nullptr)),
235 m_isLocked(std::exchange(other.m_isLocked, false))
236 {}
237
238 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMutexLocker)
239
240 inline ~QMutexLocker()
241 {
242 if (m_isLocked)
243 unlock();
244 }
245
246 inline bool isLocked() const noexcept
247 {
248 return m_isLocked;
249 }
250
251 inline void unlock() noexcept
252 {
253 Q_ASSERT(m_isLocked);
254 m_mutex->unlock();
255 m_isLocked = false;
256 }
257
258 inline void relock() QT_MUTEX_LOCK_NOEXCEPT
259 {
260 Q_ASSERT(!m_isLocked);
261 m_mutex->lock();
262 m_isLocked = true;
263 }
264
265 inline void swap(QMutexLocker &other) noexcept
266 {
267 qt_ptr_swap(m_mutex, other.m_mutex);
268 std::swap(m_isLocked, other.m_isLocked);
269 }
270
271 Mutex *mutex() const
272 {
273 return m_mutex;
274 }
275private:
276 Q_DISABLE_COPY(QMutexLocker)
277
278 Mutex *m_mutex;
279 bool m_isLocked = false;
280};
281
282#else // !QT_CONFIG(thread) && !Q_QDOC
283
285{
286public:
287
288 constexpr QMutex() noexcept { }
289
290 inline void lock() noexcept {}
291 inline bool tryLock(int timeout = 0) noexcept { Q_UNUSED(timeout); return true; }
292 inline bool try_lock() noexcept { return true; }
293 inline void unlock() noexcept {}
294
295 template <class Rep, class Period>
296 inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept
297 {
298 Q_UNUSED(duration);
299 return true;
300 }
301
302 template<class Clock, class Duration>
303 inline bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) noexcept
304 {
305 Q_UNUSED(timePoint);
306 return true;
307 }
308
309private:
310 Q_DISABLE_COPY(QMutex)
311};
312
313class QRecursiveMutex : public QMutex {};
314
315template <typename Mutex>
317{
318public:
320 inline explicit QMutexLocker(Mutex *) noexcept {}
321 inline ~QMutexLocker() noexcept {}
322
323 inline void unlock() noexcept {}
324 void relock() noexcept {}
325 inline Mutex *mutex() const noexcept { return nullptr; }
326
327private:
328 Q_DISABLE_COPY(QMutexLocker)
329};
330
332
333#endif // !QT_CONFIG(thread) && !Q_QDOC
334
336
337#endif // QMUTEX_H
\macro Q_ATOMIC_INTnn_IS_SUPPORTED
Definition qatomic.h:123
\inmodule QtCore
ForeverConstant
\value Forever Used when creating a QDeadlineTimer to indicate the deadline should not expire
static constexpr ForeverConstant Forever
\inmodule QtCore
Definition qmutex.h:317
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:323
Q_NODISCARD_CTOR QMutexLocker(Mutex *) noexcept
Constructs a QMutexLocker and locks mutex.
Definition qmutex.h:320
~QMutexLocker() noexcept
Destroys the QMutexLocker and unlocks the mutex that was locked in the constructor.
Definition qmutex.h:321
void relock() noexcept
Relocks an unlocked mutex locker.
Definition qmutex.h:324
Mutex * mutex() const noexcept
Returns the mutex on which the QMutexLocker is operating.
Definition qmutex.h:325
\inmodule QtCore
Definition qmutex.h:285
bool tryLock(int timeout=0) noexcept
Attempts to lock the mutex.
Definition qmutex.h:291
bool try_lock_for(std::chrono::duration< Rep, Period > duration) noexcept
Definition qmutex.h:296
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:293
constexpr QMutex() noexcept
Constructs a new mutex.
Definition qmutex.h:288
bool try_lock() noexcept
Definition qmutex.h:292
bool try_lock_until(std::chrono::time_point< Clock, Duration > timePoint) noexcept
Definition qmutex.h:303
void lock() noexcept
Locks the mutex.
Definition qmutex.h:290
\inmodule QtCore
Definition qmutex.h:313
Combined button and popup list for selecting options.
void mutexPostUnlock(void *, unsigned)
Definition qtsan_impl.h:73
void mutexPreUnlock(void *, unsigned)
Definition qtsan_impl.h:72
void mutexPreLock(void *, unsigned)
Definition qtsan_impl.h:70
void mutexPostLock(void *, unsigned, int)
Definition qtsan_impl.h:71
@ TryLockFailed
Definition qtsan_impl.h:68
@ TryLock
Definition qtsan_impl.h:67
#define Q_NODISCARD_CTOR
#define Q_LIKELY(x)
QMutex QBasicMutex
Definition qmutex.h:331
GLenum GLenum GLsizei count
GLbitfield GLuint64 timeout
[4]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr void qt_ptr_swap(T *&lhs, T *&rhs) noexcept
Definition qswap.h:43
#define Q_UNUSED(x)
size_t quintptr
Definition qtypes.h:72
unsigned int uint
Definition qtypes.h:29
mutex tryLock(deadline.remainingTime())
[4]
QObject::connect nullptr
QTimer * timer
[3]
QMutex mutex
[2]
QReadWriteLock lock
[0]
mutex unlock()
QSharedPointer< T > other(t)
[5]
this swap(other)