File indexing completed on 2026-05-21 08:31:17
0001
0002
0003
0004
0005 #ifndef QMUTEX_H
0006 #define QMUTEX_H
0007
0008 #include <QtCore/qglobal.h>
0009 #include <QtCore/qatomic.h>
0010 #include <QtCore/qdeadlinetimer.h>
0011 #include <QtCore/qtsan_impl.h>
0012
0013 #include <chrono>
0014
0015 QT_BEGIN_NAMESPACE
0016
0017 #if QT_CONFIG(thread) || defined(Q_QDOC)
0018
0019 class QMutex;
0020 class QRecursiveMutex;
0021 class QMutexPrivate;
0022
0023 class QT6_ONLY(Q_CORE_EXPORT) QBasicMutex
0024 {
0025 Q_DISABLE_COPY_MOVE(QBasicMutex)
0026 protected:
0027 static constexpr bool FutexAlwaysAvailable =
0028 #if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX) || defined(Q_OS_WIN)
0029 true
0030 #else
0031 false
0032 #endif
0033 ;
0034
0035 public:
0036 constexpr QBasicMutex()
0037 : d_ptr(nullptr)
0038 {}
0039
0040
0041 inline void lock() noexcept(FutexAlwaysAvailable) {
0042 QtTsan::mutexPreLock(this, 0u);
0043
0044 if (!fastTryLock())
0045 lockInternal();
0046
0047 QtTsan::mutexPostLock(this, 0u, 0);
0048 }
0049
0050
0051 inline void unlock() noexcept {
0052 Q_ASSERT(d_ptr.loadRelaxed());
0053
0054 QtTsan::mutexPreUnlock(this, 0u);
0055
0056 if constexpr (FutexAlwaysAvailable) {
0057
0058 if (QMutexPrivate *d = d_ptr.fetchAndStoreRelease(nullptr); d != dummyLocked())
0059 unlockInternalFutex(d);
0060 } else {
0061
0062 if (QMutexPrivate *d; !d_ptr.testAndSetRelease(dummyLocked(), nullptr, d))
0063 unlockInternal(d);
0064 }
0065
0066 QtTsan::mutexPostUnlock(this, 0u);
0067 }
0068
0069 bool tryLock() noexcept {
0070 unsigned tsanFlags = QtTsan::TryLock;
0071 QtTsan::mutexPreLock(this, tsanFlags);
0072
0073 const bool success = fastTryLock();
0074
0075 if (!success)
0076 tsanFlags |= QtTsan::TryLockFailed;
0077 QtTsan::mutexPostLock(this, tsanFlags, 0);
0078
0079 return success;
0080 }
0081
0082
0083 bool try_lock() noexcept { return tryLock(); }
0084
0085 private:
0086 inline bool fastTryLock() noexcept
0087 {
0088 if (d_ptr.loadRelaxed() != nullptr)
0089 return false;
0090 return d_ptr.testAndSetAcquire(nullptr, dummyLocked());
0091 }
0092 #if QT_CORE_REMOVED_SINCE(6, 10)
0093 inline bool fastTryUnlock() noexcept {
0094 return d_ptr.testAndSetRelease(dummyLocked(), nullptr);
0095 }
0096 #endif
0097
0098 QT7_ONLY(Q_CORE_EXPORT)
0099 void lockInternal() noexcept(FutexAlwaysAvailable);
0100 QT7_ONLY(Q_CORE_EXPORT)
0101 bool lockInternal(QDeadlineTimer timeout) noexcept(FutexAlwaysAvailable);
0102 #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
0103 bool lockInternal(int timeout) noexcept(FutexAlwaysAvailable);
0104 void unlockInternal() noexcept;
0105 #endif
0106 QT7_ONLY(Q_CORE_EXPORT)
0107 void unlockInternalFutex(void *d) noexcept;
0108 QT7_ONLY(Q_CORE_EXPORT)
0109 void unlockInternal(void *d) noexcept;
0110 #if QT_CORE_REMOVED_SINCE(6, 9)
0111 void destroyInternal(QMutexPrivate *d);
0112 #endif
0113 QT7_ONLY(Q_CORE_EXPORT)
0114 void destroyInternal(void *d);
0115
0116 QBasicAtomicPointer<QMutexPrivate> d_ptr;
0117 static inline QMutexPrivate *dummyLocked() {
0118 return reinterpret_cast<QMutexPrivate *>(quintptr(1));
0119 }
0120
0121 friend class QMutex;
0122 friend class QMutexPrivate;
0123 };
0124
0125 class QT6_ONLY(Q_CORE_EXPORT) QMutex : public QBasicMutex
0126 {
0127 public:
0128 constexpr QMutex() = default;
0129 ~QMutex()
0130 {
0131 QMutexPrivate *d = d_ptr.loadRelaxed();
0132 if (d)
0133 destroyInternal(d);
0134 }
0135
0136 #ifdef Q_QDOC
0137 inline void lock() noexcept(FutexAlwaysAvailable);
0138 inline void unlock() noexcept;
0139 bool tryLock() noexcept;
0140 #endif
0141
0142
0143 bool try_lock() noexcept { return tryLock(); }
0144
0145
0146 using QBasicMutex::tryLock;
0147 bool tryLock(int timeout) noexcept(FutexAlwaysAvailable)
0148 {
0149 return tryLock(QDeadlineTimer(timeout));
0150 }
0151
0152 bool tryLock(QDeadlineTimer timeout) noexcept(FutexAlwaysAvailable)
0153 {
0154 unsigned tsanFlags = QtTsan::TryLock;
0155 QtTsan::mutexPreLock(this, tsanFlags);
0156
0157 bool success = fastTryLock();
0158
0159 if (success) {
0160 QtTsan::mutexPostLock(this, tsanFlags, 0);
0161 return success;
0162 }
0163
0164 success = lockInternal(timeout);
0165
0166 if (!success)
0167 tsanFlags |= QtTsan::TryLockFailed;
0168 QtTsan::mutexPostLock(this, tsanFlags, 0);
0169
0170 return success;
0171 }
0172
0173
0174 template <class Rep, class Period>
0175 bool try_lock_for(std::chrono::duration<Rep, Period> duration)
0176 {
0177 return tryLock(QDeadlineTimer(duration));
0178 }
0179
0180
0181 template<class Clock, class Duration>
0182 bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
0183 {
0184 return tryLock(QDeadlineTimer(timePoint));
0185 }
0186 };
0187
0188 class QT6_ONLY(Q_CORE_EXPORT) QRecursiveMutex
0189 {
0190 Q_DISABLE_COPY_MOVE(QRecursiveMutex)
0191
0192
0193 QAtomicPointer<void> owner = nullptr;
0194
0195 uint count = 0;
0196 QMutex mutex;
0197 static constexpr bool LockIsNoexcept = noexcept(std::declval<QMutex>().lock());
0198
0199 public:
0200 constexpr QRecursiveMutex() = default;
0201 QT7_ONLY(Q_CORE_EXPORT)
0202 ~QRecursiveMutex();
0203
0204
0205
0206 void lock() noexcept(LockIsNoexcept)
0207 { tryLock(QDeadlineTimer(QDeadlineTimer::Forever)); }
0208 QT_CORE_INLINE_SINCE(6, 6)
0209 bool tryLock(int timeout) noexcept(LockIsNoexcept);
0210 QT7_ONLY(Q_CORE_EXPORT)
0211 bool tryLock(QDeadlineTimer timer = {}) noexcept(LockIsNoexcept);
0212
0213 QT7_ONLY(Q_CORE_EXPORT)
0214 void unlock() noexcept;
0215
0216
0217 bool try_lock() noexcept(LockIsNoexcept) { return tryLock(); }
0218
0219
0220 template <class Rep, class Period>
0221 bool try_lock_for(std::chrono::duration<Rep, Period> duration)
0222 {
0223 return tryLock(QDeadlineTimer(duration));
0224 }
0225
0226
0227 template<class Clock, class Duration>
0228 bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
0229 {
0230 return tryLock(QDeadlineTimer(timePoint));
0231 }
0232 };
0233
0234 #if QT_CORE_INLINE_IMPL_SINCE(6, 6)
0235 bool QRecursiveMutex::tryLock(int timeout) noexcept(LockIsNoexcept)
0236 {
0237 return tryLock(QDeadlineTimer(timeout));
0238 }
0239 #endif
0240
0241 template <typename Mutex>
0242 class QMutexLocker
0243 {
0244 #ifdef Q_CC_GHS
0245
0246 static constexpr bool LockIsNoexcept = false;
0247 #else
0248 static constexpr bool LockIsNoexcept = noexcept(std::declval<Mutex>().lock());
0249 #endif
0250 public:
0251 Q_NODISCARD_CTOR
0252 inline explicit QMutexLocker(Mutex *mutex) noexcept(LockIsNoexcept)
0253 {
0254 m_mutex = mutex;
0255 if (Q_LIKELY(mutex)) {
0256 mutex->lock();
0257 m_isLocked = true;
0258 }
0259 }
0260
0261 Q_NODISCARD_CTOR
0262 inline QMutexLocker(QMutexLocker &&other) noexcept
0263 : m_mutex(std::exchange(other.m_mutex, nullptr)),
0264 m_isLocked(std::exchange(other.m_isLocked, false))
0265 {}
0266
0267 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMutexLocker)
0268
0269 inline ~QMutexLocker()
0270 {
0271 if (m_isLocked)
0272 unlock();
0273 }
0274
0275 inline bool isLocked() const noexcept
0276 {
0277 return m_isLocked;
0278 }
0279
0280 inline void unlock() noexcept
0281 {
0282 Q_ASSERT(m_isLocked);
0283 m_mutex->unlock();
0284 m_isLocked = false;
0285 }
0286
0287 inline void relock() noexcept(LockIsNoexcept)
0288 {
0289 Q_ASSERT(!m_isLocked);
0290 m_mutex->lock();
0291 m_isLocked = true;
0292 }
0293
0294 inline void swap(QMutexLocker &other) noexcept
0295 {
0296 qt_ptr_swap(m_mutex, other.m_mutex);
0297 std::swap(m_isLocked, other.m_isLocked);
0298 }
0299
0300 Mutex *mutex() const
0301 {
0302 return m_mutex;
0303 }
0304 private:
0305 Q_DISABLE_COPY(QMutexLocker)
0306
0307 Mutex *m_mutex;
0308 bool m_isLocked = false;
0309 };
0310
0311 #else
0312
0313 class QMutex
0314 {
0315 public:
0316
0317 constexpr QMutex() noexcept { }
0318
0319 inline void lock() noexcept {}
0320 inline bool tryLock(int timeout = 0) noexcept { Q_UNUSED(timeout); return true; }
0321 inline bool try_lock() noexcept { return true; }
0322 inline void unlock() noexcept {}
0323
0324 template <class Rep, class Period>
0325 inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept
0326 {
0327 Q_UNUSED(duration);
0328 return true;
0329 }
0330
0331 template<class Clock, class Duration>
0332 inline bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) noexcept
0333 {
0334 Q_UNUSED(timePoint);
0335 return true;
0336 }
0337
0338 private:
0339 Q_DISABLE_COPY(QMutex)
0340 };
0341
0342 class QRecursiveMutex : public QMutex {};
0343
0344 template <typename Mutex>
0345 class QMutexLocker
0346 {
0347 public:
0348 Q_NODISCARD_CTOR
0349 inline explicit QMutexLocker(Mutex *) noexcept {}
0350 inline ~QMutexLocker() noexcept {}
0351
0352 inline void unlock() noexcept {}
0353 void relock() noexcept {}
0354 inline Mutex *mutex() const noexcept { return nullptr; }
0355
0356 private:
0357 Q_DISABLE_COPY(QMutexLocker)
0358 };
0359
0360 typedef QMutex QBasicMutex;
0361
0362 #endif
0363
0364 QT_END_NAMESPACE
0365
0366 #endif