diff options
Diffstat (limited to 'src/corelib/thread/qmutex.h')
-rw-r--r-- | src/corelib/thread/qmutex.h | 173 |
1 files changed, 90 insertions, 83 deletions
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 9042ce5f5e..c45051d03f 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -64,16 +64,43 @@ QT_BEGIN_NAMESPACE class QMutex; class QRecursiveMutex; -class QMutexData; +class QMutexPrivate; + +#if __has_include(<chrono>) +namespace QtPrivate +{ + template<class Rep, class Period> + static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration) + { + // N4606 § 30.4.1.3.5 [thread.timedmutex.requirements] specifies that a + // duration less than or equal to duration.zero() shall result in a + // try_lock, unlike QMutex's tryLock with a negative duration which + // results in a lock. + + if (duration <= duration.zero()) + return 0; + + // when converting from 'duration' to milliseconds, make sure that + // the result is not shorter than 'duration': + std::chrono::milliseconds wait = std::chrono::duration_cast<std::chrono::milliseconds>(duration); + if (wait < duration) + wait += std::chrono::milliseconds(1); + Q_ASSERT(wait >= duration); + const auto ms = wait.count(); + const auto maxInt = (std::numeric_limits<int>::max)(); + + return ms < maxInt ? int(ms) : maxInt; + } +} +#endif class Q_CORE_EXPORT QBasicMutex { + Q_DISABLE_COPY_MOVE(QBasicMutex) public: -#ifdef Q_COMPILER_CONSTEXPR constexpr QBasicMutex() : d_ptr(nullptr) {} -#endif // BasicLockable concept inline void lock() QT_MUTEX_LOCK_NOEXCEPT { @@ -94,7 +121,6 @@ public: // Lockable concept bool try_lock() noexcept { return tryLock(); } - bool isRecursive() const noexcept; private: inline bool fastTryLock() noexcept { @@ -103,62 +129,56 @@ private: inline bool fastTryUnlock() noexcept { return d_ptr.testAndSetRelease(dummyLocked(), nullptr); } - inline bool fastTryLock(QMutexData *¤t) noexcept { - return d_ptr.testAndSetAcquire(nullptr, dummyLocked(), current); - } - inline bool fastTryUnlock(QMutexData *¤t) noexcept { - return d_ptr.testAndSetRelease(dummyLocked(), nullptr, current); - } void lockInternal() QT_MUTEX_LOCK_NOEXCEPT; bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT; void unlockInternal() noexcept; + void destroyInternal(QMutexPrivate *d); - QBasicAtomicPointer<QMutexData> d_ptr; - static inline QMutexData *dummyLocked() { - return reinterpret_cast<QMutexData *>(quintptr(1)); + QBasicAtomicPointer<QMutexPrivate> d_ptr; + static inline QMutexPrivate *dummyLocked() { + return reinterpret_cast<QMutexPrivate *>(quintptr(1)); } friend class QMutex; - friend class QRecursiveMutex; - friend class QMutexData; + friend class QMutexPrivate; }; class Q_CORE_EXPORT QMutex : public QBasicMutex { public: -#if defined(Q_COMPILER_CONSTEXPR) constexpr QMutex() = default; -#else - QMutex() { d_ptr.storeRelaxed(nullptr); } -#endif -#if QT_DEPRECATED_SINCE(5,15) - enum RecursionMode { NonRecursive, Recursive }; - QT_DEPRECATED_VERSION_X(5, 15, "Use QRecursiveMutex instead of a recursive QMutex") - explicit QMutex(RecursionMode mode); - - QT_DEPRECATED_VERSION_X(5, 15, "Use QRecursiveMutex instead of a recursive QMutex") - bool isRecursive() const noexcept - { return QBasicMutex::isRecursive(); } + ~QMutex() + { + QMutexPrivate *d = d_ptr.loadRelaxed(); + if (d) + destroyInternal(d); + } + +#ifdef Q_QDOC + inline void lock() QT_MUTEX_LOCK_NOEXCEPT; + inline void unlock() noexcept; + bool tryLock() noexcept; #endif - ~QMutex(); + // Lockable concept + bool try_lock() noexcept { return tryLock(); } - // BasicLockable concept - void lock() QT_MUTEX_LOCK_NOEXCEPT; - bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; - // BasicLockable concept - void unlock() noexcept; - // Lockable concept - bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } + using QBasicMutex::tryLock; + bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT + { + if (fastTryLock()) + return true; + return lockInternal(timeout); + } #if __has_include(<chrono>) || defined(Q_CLANG_QDOC) // TimedLockable concept template <class Rep, class Period> bool try_lock_for(std::chrono::duration<Rep, Period> duration) { - return tryLock(convertToMilliseconds(duration)); + return tryLock(QtPrivate::convertToMilliseconds(duration)); } // TimedLockable concept @@ -171,56 +191,45 @@ public: return try_lock_for(timePoint - Clock::now()); } #endif +}; -private: - Q_DISABLE_COPY(QMutex) - template<typename Mutex> - friend class QMutexLocker; - friend class QRecursiveMutex; - friend class ::tst_QMutex; +class QRecursiveMutexPrivate; +class Q_CORE_EXPORT QRecursiveMutex +{ + Q_DISABLE_COPY_MOVE(QRecursiveMutex) + QRecursiveMutexPrivate *d; +public: -#if __has_include(<chrono>) - template<class Rep, class Period> - static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration) - { - // N4606 § 30.4.1.3.5 [thread.timedmutex.requirements] specifies that a - // duration less than or equal to duration.zero() shall result in a - // try_lock, unlike QMutex's tryLock with a negative duration which - // results in a lock. + QRecursiveMutex(); + ~QRecursiveMutex(); - if (duration <= duration.zero()) - return 0; - // when converting from 'duration' to milliseconds, make sure that - // the result is not shorter than 'duration': - std::chrono::milliseconds wait = std::chrono::duration_cast<std::chrono::milliseconds>(duration); - if (wait < duration) - wait += std::chrono::milliseconds(1); - Q_ASSERT(wait >= duration); - const auto ms = wait.count(); - const auto maxInt = (std::numeric_limits<int>::max)(); + // BasicLockable concept + void lock() QT_MUTEX_LOCK_NOEXCEPT; + bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; + // BasicLockable concept + void unlock() noexcept; - return ms < maxInt ? int(ms) : maxInt; + // Lockable concept + bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } + +#if __has_include(<chrono>) || defined(Q_CLANG_QDOC) + // TimedLockable concept + template <class Rep, class Period> + bool try_lock_for(std::chrono::duration<Rep, Period> duration) + { + return tryLock(QtPrivate::convertToMilliseconds(duration)); } -#endif -}; -class QRecursiveMutex : private QMutex -{ - // ### Qt 6: make it independent of QMutex - template<typename Mutex> - friend class QMutexLocker; -public: - Q_CORE_EXPORT QRecursiveMutex(); - Q_CORE_EXPORT ~QRecursiveMutex(); + // TimedLockable concept + template<class Clock, class Duration> + bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) + { + // Implemented in terms of try_lock_for to honor the similar + // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12. - using QMutex::lock; - using QMutex::tryLock; - using QMutex::unlock; - using QMutex::try_lock; -#if __has_include(<chrono>) - using QMutex::try_lock_for; - using QMutex::try_lock_until; + return try_lock_for(timePoint - Clock::now()); + } #endif }; @@ -271,18 +280,16 @@ private: #else // !QT_CONFIG(thread) && !Q_CLANG_QDOC -class Q_CORE_EXPORT QMutex +class QMutex { public: - enum RecursionMode { NonRecursive, Recursive }; - inline constexpr explicit QMutex(RecursionMode = NonRecursive) noexcept { } + inline constexpr explicit QMutex() noexcept { } inline void lock() noexcept {} inline bool tryLock(int timeout = 0) noexcept { Q_UNUSED(timeout); return true; } inline bool try_lock() noexcept { return true; } inline void unlock() noexcept {} - inline bool isRecursive() const noexcept { return true; } #if __has_include(<chrono>) template <class Rep, class Period> @@ -306,7 +313,7 @@ private: class QRecursiveMutex : public QMutex {}; -template<typename Mutex> +template <typename Mutex> class QMutexLocker { public: |