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