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