QMutexLocker: add move semantics

The class is similar to unique_lock in that it allows for unlocking
and relocking. Since the locked state is tracked by QMutexLocker itself,
it's trivial to make it movable.

[ChangeLog][QtCore][QMutexLocker] The class is now movable.

Change-Id: I534044f8024575e996c12efb2236761d493798a3
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
This commit is contained in:
Giuseppe D'Angelo 2022-03-06 13:34:15 +01:00
parent 4b8c20a297
commit 20d0ff1a39
3 changed files with 114 additions and 0 deletions

View File

@ -485,6 +485,40 @@ void QRecursiveMutex::unlock() noexcept
\sa QMutex::lock()
*/
/*!
\fn template <typename Mutex> QMutexLocker<Mutex>::QMutexLocker(QMutexLocker &&other) noexcept
\since 6.4
Move-constructs a QMutexLocker from \a other. The mutex and the
state of \a other is transferred to the newly constructed instance.
After the move, \a other will no longer be managing its mutex.
\sa QMutex::lock()
*/
/*!
\fn template <typename Mutex> QMutexLocker<Mutex> &QMutexLocker<Mutex>::operator=(QMutexLocker &&other) noexcept
\since 6.4
Move-assigns \a other onto this QMutexLocker. If this QMutexLocker
was holding a locked mutex before the assignment, the mutex will be
unlocked. The mutex and the state of \a other is then transferred
to this QMutexLocker. After the move, \a other will no longer be
managing its mutex.
\sa QMutex::lock()
*/
/*!
\fn template <typename Mutex> void QMutexLocker<Mutex>::swap(QMutexLocker &other) noexcept
\since 6.4
Swaps the mutex and the state of this QMutexLocker with \a other.
This operation is very fast and never fails.
\sa QMutex::lock()
*/
/*!
\fn template <typename Mutex> QMutexLocker<Mutex>::~QMutexLocker() noexcept

View File

@ -247,6 +247,13 @@ public:
}
}
inline QMutexLocker(QMutexLocker &&other) noexcept
: m_mutex(std::exchange(other.m_mutex, nullptr)),
m_isLocked(std::exchange(other.m_isLocked, false))
{}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QMutexLocker)
inline ~QMutexLocker()
{
unlock();
@ -275,6 +282,12 @@ public:
}
}
inline void swap(QMutexLocker &other) noexcept
{
qt_ptr_swap(m_mutex, other.m_mutex);
std::swap(m_isLocked, other.m_isLocked);
}
Mutex *mutex() const
{
return m_mutex;

View File

@ -67,6 +67,7 @@ private slots:
void scopeTest();
void unlockAndRelockTest();
void lockerStateTest();
void moveSemantics();
};
void tst_QMutexLocker::scopeTest()
@ -214,5 +215,71 @@ void tst_QMutexLocker::lockerStateTest()
thread = nullptr;
}
void tst_QMutexLocker::moveSemantics()
{
{
QMutexLocker<QMutex> locker(nullptr);
QVERIFY(!locker.isLocked());
QCOMPARE(locker.mutex(), nullptr);
QMutexLocker locker2(std::move(locker));
QVERIFY(!locker.isLocked());
QVERIFY(!locker2.isLocked());
QCOMPARE(locker.mutex(), nullptr);
QCOMPARE(locker2.mutex(), nullptr);
}
QMutex mutex;
{
QMutexLocker locker(&mutex);
QVERIFY(locker.isLocked());
QCOMPARE(locker.mutex(), &mutex);
QVERIFY(!mutex.tryLock());
QMutexLocker locker2(std::move(locker));
QVERIFY(!locker.isLocked());
QVERIFY(locker2.isLocked());
QCOMPARE(locker.mutex(), nullptr);
QCOMPARE(locker2.mutex(), &mutex);
QVERIFY(!mutex.tryLock());
}
QVERIFY(mutex.tryLock());
mutex.unlock();
{
QMutex mutex;
QMutexLocker locker(&mutex);
QVERIFY(locker.isLocked());
QCOMPARE(locker.mutex(), &mutex);
QVERIFY(!mutex.tryLock());
locker.unlock();
QVERIFY(!locker.isLocked());
QCOMPARE(locker.mutex(), &mutex);
QVERIFY(mutex.tryLock());
mutex.unlock();
QMutexLocker locker2(std::move(locker));
QVERIFY(!locker.isLocked());
QVERIFY(!locker2.isLocked());
QCOMPARE(locker.mutex(), nullptr);
QCOMPARE(locker2.mutex(), &mutex);
QVERIFY(mutex.tryLock());
mutex.unlock();
locker2.relock();
QVERIFY(!locker.isLocked());
QVERIFY(locker2.isLocked());
QCOMPARE(locker.mutex(), nullptr);
QCOMPARE(locker2.mutex(), &mutex);
QVERIFY(!mutex.tryLock());
}
QVERIFY(mutex.tryLock());
mutex.unlock();
}
QTEST_MAIN(tst_QMutexLocker)
#include "tst_qmutexlocker.moc"