diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp index 36f051408e3..acbb62432f1 100644 --- a/src/corelib/thread/qreadwritelock.cpp +++ b/src/corelib/thread/qreadwritelock.cpp @@ -31,7 +31,7 @@ QT_BEGIN_NAMESPACE using namespace QReadWriteLockStates; namespace { -using ms = std::chrono::milliseconds; +using steady_clock = std::chrono::steady_clock; const auto dummyLockedForRead = reinterpret_cast(quintptr(StateLockedForRead)); const auto dummyLockedForWrite = reinterpret_cast(quintptr(StateLockedForWrite)); @@ -40,9 +40,9 @@ inline bool isUncontendedLocked(const QReadWriteLockPrivate *d) } static bool contendedTryLockForRead(QAtomicPointer &d_ptr, - int timeout, QReadWriteLockPrivate *d); + QDeadlineTimer timeout, QReadWriteLockPrivate *d); static bool contendedTryLockForWrite(QAtomicPointer &d_ptr, - int timeout, QReadWriteLockPrivate *d); + QDeadlineTimer timeout, QReadWriteLockPrivate *d); /*! \class QReadWriteLock \inmodule QtCore @@ -143,6 +143,7 @@ QReadWriteLock::~QReadWriteLock() */ /*! + \fn bool QReadWriteLock::tryLockForRead(int timeout) Attempts to lock for reading. This function returns \c true if the lock was obtained; otherwise it returns \c false. If another thread @@ -161,7 +162,25 @@ QReadWriteLock::~QReadWriteLock() \sa unlock(), lockForRead() */ -bool QReadWriteLock::tryLockForRead(int timeout) + +/*! + \overload + \since 6.6 + + Attempts to lock for reading. This function returns \c true if the lock was + obtained; otherwise it returns \c false. If another thread has locked for + writing, this function will wait until \a timeout expires for the lock to + become available. + + If the lock was obtained, the lock must be unlocked with unlock() + before another thread can successfully lock it for writing. + + It is not possible to lock for read if the thread already has + locked for write. + + \sa unlock(), lockForRead() +*/ +bool QReadWriteLock::tryLockForRead(QDeadlineTimer timeout) { // Fast case: non contended: QReadWriteLockPrivate *d = d_ptr.loadRelaxed(); @@ -171,7 +190,7 @@ bool QReadWriteLock::tryLockForRead(int timeout) } Q_NEVER_INLINE static bool contendedTryLockForRead(QAtomicPointer &d_ptr, - int timeout, QReadWriteLockPrivate *d) + QDeadlineTimer timeout, QReadWriteLockPrivate *d) { while (true) { if (d == nullptr) { @@ -191,7 +210,7 @@ Q_NEVER_INLINE static bool contendedTryLockForRead(QAtomicPointer &d_ptr, - int timeout, QReadWriteLockPrivate *d) + QDeadlineTimer timeout, QReadWriteLockPrivate *d) { while (true) { if (d == nullptr) { @@ -276,7 +315,7 @@ Q_NEVER_INLINE static bool contendedTryLockForWrite(QAtomicPointer &lock, int timeout) +bool QReadWriteLockPrivate::lockForRead(std::unique_lock &lock, QDeadlineTimer timeout) { Q_ASSERT(!mutex.try_lock()); // mutex must be locked when entering this function - QElapsedTimer t; - if (timeout > 0) - t.start(); - while (waitingWriters || writerCount) { - if (timeout == 0) + if (timeout.hasExpired()) return false; - if (timeout > 0) { - auto elapsed = t.elapsed(); - if (elapsed > timeout) - return false; + if (!timeout.isForever()) { waitingReaders++; - readerCond.wait_for(lock, ms{timeout - elapsed}); + readerCond.wait_until(lock, timeout.deadline()); } else { waitingReaders++; readerCond.wait(lock); @@ -398,29 +430,22 @@ bool QReadWriteLockPrivate::lockForRead(std::unique_lock &lock return true; } -bool QReadWriteLockPrivate::lockForWrite(std::unique_lock &lock, int timeout) +bool QReadWriteLockPrivate::lockForWrite(std::unique_lock &lock, QDeadlineTimer timeout) { Q_ASSERT(!mutex.try_lock()); // mutex must be locked when entering this function - QElapsedTimer t; - if (timeout > 0) - t.start(); - while (readerCount || writerCount) { - if (timeout == 0) - return false; - if (timeout > 0) { - auto elapsed = t.elapsed(); - if (elapsed > timeout) { - if (waitingReaders && !waitingWriters && !writerCount) { - // We timed out and now there is no more writers or waiting writers, but some - // readers were queued (probably because of us). Wake the waiting readers. - readerCond.notify_all(); - } - return false; + if (timeout.hasExpired()) { + if (waitingReaders && !waitingWriters && !writerCount) { + // We timed out and now there is no more writers or waiting writers, but some + // readers were queued (probably because of us). Wake the waiting readers. + readerCond.notify_all(); } + return false; + } + if (!timeout.isForever()) { waitingWriters++; - writerCond.wait_for(lock, ms{timeout - elapsed}); + writerCond.wait_until(lock, timeout.deadline()); } else { waitingWriters++; writerCond.wait(lock); @@ -448,7 +473,7 @@ static auto handleEquals(Qt::HANDLE handle) return [handle](QReadWriteLockPrivate::Reader reader) { return reader.handle == handle; }; } -bool QReadWriteLockPrivate::recursiveLockForRead(int timeout) +bool QReadWriteLockPrivate::recursiveLockForRead(QDeadlineTimer timeout) { Q_ASSERT(recursive); auto lock = qt_unique_lock(mutex); @@ -470,7 +495,7 @@ bool QReadWriteLockPrivate::recursiveLockForRead(int timeout) return true; } -bool QReadWriteLockPrivate::recursiveLockForWrite(int timeout) +bool QReadWriteLockPrivate::recursiveLockForWrite(QDeadlineTimer timeout) { Q_ASSERT(recursive); auto lock = qt_unique_lock(mutex); diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h index 4db44784e33..0494088bee0 100644 --- a/src/corelib/thread/qreadwritelock.h +++ b/src/corelib/thread/qreadwritelock.h @@ -5,10 +5,10 @@ #define QREADWRITELOCK_H #include +#include QT_BEGIN_NAMESPACE - #if QT_CONFIG(thread) class QReadWriteLockPrivate; @@ -26,17 +26,30 @@ public: #if QT_CORE_REMOVED_SINCE(6, 6) bool tryLockForRead(); #endif - bool tryLockForRead(int timeout = 0); + QT_CORE_INLINE_SINCE(6, 6) + bool tryLockForRead(int timeout); + bool tryLockForRead(QDeadlineTimer timeout = {}); QT_CORE_INLINE_SINCE(6, 6) void lockForWrite(); #if QT_CORE_REMOVED_SINCE(6, 6) bool tryLockForWrite(); #endif - bool tryLockForWrite(int timeout = 0); + QT_CORE_INLINE_SINCE(6, 6) + bool tryLockForWrite(int timeout); + bool tryLockForWrite(QDeadlineTimer timeout = {}); void unlock(); +#ifndef Q_QDOC + // because tryLockForXxx(QDeadlineTimer::Forever) is the same + // as tryLockForXxx(0), which is not forever + bool tryLockForRead(QDeadlineTimer::ForeverConstant) + { lockForRead(); return true; } + bool tryLockForWrite(QDeadlineTimer::ForeverConstant) + { lockForWrite(); return true; } +#endif + private: Q_DISABLE_COPY(QReadWriteLock) QAtomicPointer d_ptr; @@ -46,12 +59,22 @@ private: #if QT_CORE_INLINE_IMPL_SINCE(6, 6) void QReadWriteLock::lockForRead() { - tryLockForRead(-1); + tryLockForRead(QDeadlineTimer(QDeadlineTimer::Forever)); +} + +bool QReadWriteLock::tryLockForRead(int timeout) +{ + return tryLockForRead(QDeadlineTimer(timeout)); } void QReadWriteLock::lockForWrite() { - tryLockForWrite(-1); + tryLockForWrite(QDeadlineTimer(QDeadlineTimer::Forever)); +} + +bool QReadWriteLock::tryLockForWrite(int timeout) +{ + return tryLockForWrite(QDeadlineTimer(timeout)); } #endif // inline since 6.6 @@ -164,10 +187,12 @@ public: void lockForRead() noexcept { } bool tryLockForRead() noexcept { return true; } + bool tryLockForRead(QDeadlineTimer) noexcept { return true; } bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; } void lockForWrite() noexcept { } bool tryLockForWrite() noexcept { return true; } + bool tryLockForWrite(QDeadlineTimer) noexcept { return true; } bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; } void unlock() noexcept { } diff --git a/src/corelib/thread/qreadwritelock_p.h b/src/corelib/thread/qreadwritelock_p.h index e8379fcb568..d1f887eb45b 100644 --- a/src/corelib/thread/qreadwritelock_p.h +++ b/src/corelib/thread/qreadwritelock_p.h @@ -55,8 +55,8 @@ public: const bool recursive; //Called with the mutex locked - bool lockForWrite(std::unique_lock &lock, int timeout); - bool lockForRead(std::unique_lock &lock, int timeout); + bool lockForWrite(std::unique_lock &lock, QDeadlineTimer timeout); + bool lockForRead(std::unique_lock &lock, QDeadlineTimer timeout); void unlock(); //memory management @@ -75,8 +75,8 @@ public: QVarLengthArray currentReaders; // called with the mutex unlocked - bool recursiveLockForWrite(int timeout); - bool recursiveLockForRead(int timeout); + bool recursiveLockForWrite(QDeadlineTimer timeout); + bool recursiveLockForRead(QDeadlineTimer timeout); void recursiveUnlock(); static QReadWriteLockStates::StateForWaitCondition