2022-05-10 10:06:48 +00:00
|
|
|
// Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
#ifndef QMUTEX_H
|
|
|
|
#define QMUTEX_H
|
|
|
|
|
|
|
|
#include <QtCore/qglobal.h>
|
|
|
|
#include <QtCore/qatomic.h>
|
2022-04-10 10:29:47 +00:00
|
|
|
#include <QtCore/qtsan_impl.h>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <new>
|
|
|
|
|
2019-12-08 22:47:10 +00:00
|
|
|
#if __has_include(<chrono>)
|
2016-07-14 14:37:55 +00:00
|
|
|
# include <chrono>
|
QMutex: make sure we try_lock_for no shorter than the duration passed
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
allowed code such as
mutex.try_lock_for(10us)
to compile, which is misleading, since it's actually a zero-
timeout try_lock().
Feedback from the std-discussions mailing list is that the
wait_for functions should wait for _at least_ the duration
given, because that is the natural direction of variance
(tasks becoming ready to run might not get a CPU immediately,
causing delays), while an interface that documents to wait
_no more_ than the given duration is promising something it
cannot fulfill.
Fix by converting the given duration to the smallest number
of milliseconds not less than the original duration. If that
is not representable in an int, use INT_MAX, emulating the
effect of a spurious wakeup, which are allowed to happen if
the function returns false in that case.
In the above example, the try_lock_for call is now equivalent
to
mutex.tryLock(1);
The tryLock() docs state that the actual waiting time does
not exceed the given milliseconds, but fixing that is a
separate issue.
Change-Id: Id4cbbea0ecc6fd2f94bb5aef28a1658be3728e52
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2016-10-17 11:00:04 +00:00
|
|
|
# include <limits>
|
2016-07-14 14:37:55 +00:00
|
|
|
#endif
|
|
|
|
|
QMutex: make sure we try_lock_for no shorter than the duration passed
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
allowed code such as
mutex.try_lock_for(10us)
to compile, which is misleading, since it's actually a zero-
timeout try_lock().
Feedback from the std-discussions mailing list is that the
wait_for functions should wait for _at least_ the duration
given, because that is the natural direction of variance
(tasks becoming ready to run might not get a CPU immediately,
causing delays), while an interface that documents to wait
_no more_ than the given duration is promising something it
cannot fulfill.
Fix by converting the given duration to the smallest number
of milliseconds not less than the original duration. If that
is not representable in an int, use INT_MAX, emulating the
effect of a spurious wakeup, which are allowed to happen if
the function returns false in that case.
In the above example, the try_lock_for call is now equivalent
to
mutex.tryLock(1);
The tryLock() docs state that the actual waiting time does
not exceed the given milliseconds, but fixing that is a
separate issue.
Change-Id: Id4cbbea0ecc6fd2f94bb5aef28a1658be3728e52
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2016-10-17 11:00:04 +00:00
|
|
|
class tst_QMutex;
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
|
|
|
2016-12-29 16:11:24 +00:00
|
|
|
#if QT_CONFIG(thread) || defined(Q_CLANG_QDOC)
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-08-02 14:15:22 +00:00
|
|
|
#ifdef Q_OS_LINUX
|
2019-04-02 08:54:54 +00:00
|
|
|
# define QT_MUTEX_LOCK_NOEXCEPT noexcept
|
2012-08-02 14:15:22 +00:00
|
|
|
#else
|
|
|
|
# define QT_MUTEX_LOCK_NOEXCEPT
|
|
|
|
#endif
|
|
|
|
|
2019-06-26 21:41:40 +00:00
|
|
|
class QMutex;
|
|
|
|
class QRecursiveMutex;
|
2020-09-04 13:35:16 +00:00
|
|
|
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
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2011-07-02 13:13:12 +00:00
|
|
|
class Q_CORE_EXPORT QBasicMutex
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2020-09-04 13:35:16 +00:00
|
|
|
Q_DISABLE_COPY_MOVE(QBasicMutex)
|
2011-04-27 10:05:43 +00:00
|
|
|
public:
|
2017-11-12 22:15:28 +00:00
|
|
|
constexpr QBasicMutex()
|
|
|
|
: d_ptr(nullptr)
|
|
|
|
{}
|
|
|
|
|
2016-07-14 14:37:55 +00:00
|
|
|
// BasicLockable concept
|
2012-08-02 14:15:22 +00:00
|
|
|
inline void lock() QT_MUTEX_LOCK_NOEXCEPT {
|
2022-04-10 10:29:47 +00:00
|
|
|
QtTsan::mutexPreLock(this, 0u);
|
|
|
|
|
2011-07-02 13:13:12 +00:00
|
|
|
if (!fastTryLock())
|
|
|
|
lockInternal();
|
2022-04-10 10:29:47 +00:00
|
|
|
|
|
|
|
QtTsan::mutexPostLock(this, 0u, 0);
|
2011-07-02 13:13:12 +00:00
|
|
|
}
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2016-07-14 14:37:55 +00:00
|
|
|
// BasicLockable concept
|
2019-04-02 08:54:54 +00:00
|
|
|
inline void unlock() noexcept {
|
2019-06-10 09:08:29 +00:00
|
|
|
Q_ASSERT(d_ptr.loadRelaxed()); //mutex must be locked
|
2022-04-10 10:29:47 +00:00
|
|
|
|
|
|
|
QtTsan::mutexPreUnlock(this, 0u);
|
|
|
|
|
2012-08-11 14:45:14 +00:00
|
|
|
if (!fastTryUnlock())
|
2011-07-02 13:13:12 +00:00
|
|
|
unlockInternal();
|
2022-04-10 10:29:47 +00:00
|
|
|
|
|
|
|
QtTsan::mutexPostUnlock(this, 0u);
|
2011-07-02 13:13:12 +00:00
|
|
|
}
|
|
|
|
|
2019-04-02 08:54:54 +00:00
|
|
|
bool tryLock() noexcept {
|
2022-04-10 10:29:47 +00:00
|
|
|
unsigned tsanFlags = QtTsan::TryLock;
|
|
|
|
QtTsan::mutexPreLock(this, tsanFlags);
|
|
|
|
|
|
|
|
const bool success = fastTryLock();
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
tsanFlags |= QtTsan::TryLockFailed;
|
|
|
|
QtTsan::mutexPostLock(this, tsanFlags, 0);
|
|
|
|
|
|
|
|
return success;
|
2011-07-02 13:13:12 +00:00
|
|
|
}
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2016-07-14 14:37:55 +00:00
|
|
|
// Lockable concept
|
2019-04-02 08:54:54 +00:00
|
|
|
bool try_lock() noexcept { return tryLock(); }
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
private:
|
2019-04-02 08:54:54 +00:00
|
|
|
inline bool fastTryLock() noexcept {
|
2017-09-18 09:49:52 +00:00
|
|
|
return d_ptr.testAndSetAcquire(nullptr, dummyLocked());
|
2011-07-02 13:13:12 +00:00
|
|
|
}
|
2019-04-02 08:54:54 +00:00
|
|
|
inline bool fastTryUnlock() noexcept {
|
2017-09-18 09:49:52 +00:00
|
|
|
return d_ptr.testAndSetRelease(dummyLocked(), nullptr);
|
2012-08-11 14:45:14 +00:00
|
|
|
}
|
|
|
|
|
2012-08-11 10:18:45 +00:00
|
|
|
void lockInternal() QT_MUTEX_LOCK_NOEXCEPT;
|
|
|
|
bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT;
|
2019-04-02 08:54:54 +00:00
|
|
|
void unlockInternal() noexcept;
|
2020-09-04 13:35:16 +00:00
|
|
|
void destroyInternal(QMutexPrivate *d);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
QBasicAtomicPointer<QMutexPrivate> d_ptr;
|
|
|
|
static inline QMutexPrivate *dummyLocked() {
|
|
|
|
return reinterpret_cast<QMutexPrivate *>(quintptr(1));
|
2011-07-02 13:13:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
friend class QMutex;
|
2020-09-04 13:35:16 +00:00
|
|
|
friend class QMutexPrivate;
|
2011-07-02 13:13:12 +00:00
|
|
|
};
|
|
|
|
|
2016-04-25 23:42:11 +00:00
|
|
|
class Q_CORE_EXPORT QMutex : public QBasicMutex
|
|
|
|
{
|
2011-07-02 13:13:12 +00:00
|
|
|
public:
|
2019-06-26 21:41:40 +00:00
|
|
|
constexpr QMutex() = default;
|
2020-09-04 13:35:16 +00:00
|
|
|
~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;
|
2020-09-04 08:40:29 +00:00
|
|
|
#endif
|
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
// Lockable concept
|
|
|
|
bool try_lock() noexcept { return tryLock(); }
|
2012-05-23 08:26:07 +00:00
|
|
|
|
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
using QBasicMutex::tryLock;
|
|
|
|
bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
|
|
|
|
{
|
2022-04-10 10:29:47 +00:00
|
|
|
unsigned tsanFlags = QtTsan::TryLock;
|
|
|
|
QtTsan::mutexPreLock(this, tsanFlags);
|
|
|
|
|
|
|
|
bool success = fastTryLock();
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
QtTsan::mutexPostLock(this, tsanFlags, 0);
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
success = lockInternal(timeout);
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
tsanFlags |= QtTsan::TryLockFailed;
|
|
|
|
QtTsan::mutexPostLock(this, tsanFlags, 0);
|
|
|
|
|
|
|
|
return success;
|
2020-09-04 13:35:16 +00:00
|
|
|
}
|
2016-07-14 14:37:55 +00:00
|
|
|
|
|
|
|
// TimedLockable concept
|
|
|
|
template <class Rep, class Period>
|
|
|
|
bool try_lock_for(std::chrono::duration<Rep, Period> duration)
|
|
|
|
{
|
2020-09-04 13:35:16 +00:00
|
|
|
return tryLock(QtPrivate::convertToMilliseconds(duration));
|
2016-07-14 14:37:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2016-09-13 21:20:37 +00:00
|
|
|
// requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12.
|
2016-07-14 14:37:55 +00:00
|
|
|
|
|
|
|
return try_lock_for(timePoint - Clock::now());
|
|
|
|
}
|
2020-09-04 13:35:16 +00:00
|
|
|
};
|
2016-07-14 14:37:55 +00:00
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
class Q_CORE_EXPORT QRecursiveMutex
|
|
|
|
{
|
|
|
|
Q_DISABLE_COPY_MOVE(QRecursiveMutex)
|
2020-09-10 07:54:51 +00:00
|
|
|
// written to by the thread that first owns 'mutex';
|
|
|
|
// read during attempts to acquire ownership of 'mutex' from any other thread:
|
|
|
|
QAtomicPointer<void> owner = nullptr;
|
|
|
|
// only ever accessed from the thread that owns 'mutex':
|
|
|
|
uint count = 0;
|
|
|
|
QMutex mutex;
|
QMutex: make sure we try_lock_for no shorter than the duration passed
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
allowed code such as
mutex.try_lock_for(10us)
to compile, which is misleading, since it's actually a zero-
timeout try_lock().
Feedback from the std-discussions mailing list is that the
wait_for functions should wait for _at least_ the duration
given, because that is the natural direction of variance
(tasks becoming ready to run might not get a CPU immediately,
causing delays), while an interface that documents to wait
_no more_ than the given duration is promising something it
cannot fulfill.
Fix by converting the given duration to the smallest number
of milliseconds not less than the original duration. If that
is not representable in an int, use INT_MAX, emulating the
effect of a spurious wakeup, which are allowed to happen if
the function returns false in that case.
In the above example, the try_lock_for call is now equivalent
to
mutex.tryLock(1);
The tryLock() docs state that the actual waiting time does
not exceed the given milliseconds, but fixing that is a
separate issue.
Change-Id: Id4cbbea0ecc6fd2f94bb5aef28a1658be3728e52
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2016-10-17 11:00:04 +00:00
|
|
|
|
2020-09-10 07:54:51 +00:00
|
|
|
public:
|
|
|
|
constexpr QRecursiveMutex() = default;
|
2020-09-04 13:35:16 +00:00
|
|
|
~QRecursiveMutex();
|
QMutex: make sure we try_lock_for no shorter than the duration passed
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
allowed code such as
mutex.try_lock_for(10us)
to compile, which is misleading, since it's actually a zero-
timeout try_lock().
Feedback from the std-discussions mailing list is that the
wait_for functions should wait for _at least_ the duration
given, because that is the natural direction of variance
(tasks becoming ready to run might not get a CPU immediately,
causing delays), while an interface that documents to wait
_no more_ than the given duration is promising something it
cannot fulfill.
Fix by converting the given duration to the smallest number
of milliseconds not less than the original duration. If that
is not representable in an int, use INT_MAX, emulating the
effect of a spurious wakeup, which are allowed to happen if
the function returns false in that case.
In the above example, the try_lock_for call is now equivalent
to
mutex.tryLock(1);
The tryLock() docs state that the actual waiting time does
not exceed the given milliseconds, but fixing that is a
separate issue.
Change-Id: Id4cbbea0ecc6fd2f94bb5aef28a1658be3728e52
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2016-10-17 11:00:04 +00:00
|
|
|
|
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
// BasicLockable concept
|
2020-09-10 07:54:51 +00:00
|
|
|
void lock() QT_MUTEX_LOCK_NOEXCEPT
|
|
|
|
{ tryLock(-1); }
|
2020-09-04 13:35:16 +00:00
|
|
|
bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT;
|
|
|
|
// BasicLockable concept
|
|
|
|
void unlock() noexcept;
|
QMutex: make sure we try_lock_for no shorter than the duration passed
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
allowed code such as
mutex.try_lock_for(10us)
to compile, which is misleading, since it's actually a zero-
timeout try_lock().
Feedback from the std-discussions mailing list is that the
wait_for functions should wait for _at least_ the duration
given, because that is the natural direction of variance
(tasks becoming ready to run might not get a CPU immediately,
causing delays), while an interface that documents to wait
_no more_ than the given duration is promising something it
cannot fulfill.
Fix by converting the given duration to the smallest number
of milliseconds not less than the original duration. If that
is not representable in an int, use INT_MAX, emulating the
effect of a spurious wakeup, which are allowed to happen if
the function returns false in that case.
In the above example, the try_lock_for call is now equivalent
to
mutex.tryLock(1);
The tryLock() docs state that the actual waiting time does
not exceed the given milliseconds, but fixing that is a
separate issue.
Change-Id: Id4cbbea0ecc6fd2f94bb5aef28a1658be3728e52
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2016-10-17 11:00:04 +00:00
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
// Lockable concept
|
|
|
|
bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); }
|
|
|
|
|
|
|
|
// TimedLockable concept
|
|
|
|
template <class Rep, class Period>
|
|
|
|
bool try_lock_for(std::chrono::duration<Rep, Period> duration)
|
|
|
|
{
|
|
|
|
return tryLock(QtPrivate::convertToMilliseconds(duration));
|
QMutex: make sure we try_lock_for no shorter than the duration passed
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
allowed code such as
mutex.try_lock_for(10us)
to compile, which is misleading, since it's actually a zero-
timeout try_lock().
Feedback from the std-discussions mailing list is that the
wait_for functions should wait for _at least_ the duration
given, because that is the natural direction of variance
(tasks becoming ready to run might not get a CPU immediately,
causing delays), while an interface that documents to wait
_no more_ than the given duration is promising something it
cannot fulfill.
Fix by converting the given duration to the smallest number
of milliseconds not less than the original duration. If that
is not representable in an int, use INT_MAX, emulating the
effect of a spurious wakeup, which are allowed to happen if
the function returns false in that case.
In the above example, the try_lock_for call is now equivalent
to
mutex.tryLock(1);
The tryLock() docs state that the actual waiting time does
not exceed the given milliseconds, but fixing that is a
separate issue.
Change-Id: Id4cbbea0ecc6fd2f94bb5aef28a1658be3728e52
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
2016-10-17 11:00:04 +00:00
|
|
|
}
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
// 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.
|
2019-06-26 21:41:40 +00:00
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
return try_lock_for(timePoint - Clock::now());
|
|
|
|
}
|
2019-06-26 21:41:40 +00:00
|
|
|
};
|
|
|
|
|
2020-09-04 08:41:56 +00:00
|
|
|
template <typename Mutex>
|
2021-09-18 09:29:23 +00:00
|
|
|
class [[nodiscard]] QMutexLocker
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
public:
|
2020-09-04 08:41:56 +00:00
|
|
|
inline explicit QMutexLocker(Mutex *mutex) QT_MUTEX_LOCK_NOEXCEPT
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2022-03-06 13:29:54 +00:00
|
|
|
m_mutex = mutex;
|
2020-09-04 08:41:56 +00:00
|
|
|
if (Q_LIKELY(mutex)) {
|
|
|
|
mutex->lock();
|
2022-03-06 13:29:54 +00:00
|
|
|
m_isLocked = true;
|
2012-08-01 15:54:32 +00:00
|
|
|
}
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
2022-03-06 13:29:54 +00:00
|
|
|
|
2022-03-06 12:34:15 +00:00
|
|
|
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)
|
|
|
|
|
2022-03-06 13:29:54 +00:00
|
|
|
inline ~QMutexLocker()
|
|
|
|
{
|
2022-03-06 14:12:51 +00:00
|
|
|
if (m_isLocked)
|
|
|
|
unlock();
|
2020-09-04 08:41:56 +00:00
|
|
|
}
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2022-03-06 13:31:49 +00:00
|
|
|
inline bool isLocked() const noexcept
|
|
|
|
{
|
|
|
|
return m_isLocked;
|
|
|
|
}
|
|
|
|
|
2019-04-02 08:54:54 +00:00
|
|
|
inline void unlock() noexcept
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2022-03-06 14:12:51 +00:00
|
|
|
Q_ASSERT(m_isLocked);
|
2022-03-06 13:29:54 +00:00
|
|
|
m_mutex->unlock();
|
|
|
|
m_isLocked = false;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2012-08-02 14:15:22 +00:00
|
|
|
inline void relock() QT_MUTEX_LOCK_NOEXCEPT
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2022-03-06 14:12:51 +00:00
|
|
|
Q_ASSERT(!m_isLocked);
|
|
|
|
m_mutex->lock();
|
|
|
|
m_isLocked = true;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
2022-03-06 12:34:15 +00:00
|
|
|
inline void swap(QMutexLocker &other) noexcept
|
|
|
|
{
|
|
|
|
qt_ptr_swap(m_mutex, other.m_mutex);
|
|
|
|
std::swap(m_isLocked, other.m_isLocked);
|
|
|
|
}
|
|
|
|
|
2020-09-04 08:41:56 +00:00
|
|
|
Mutex *mutex() const
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
2022-03-06 13:29:54 +00:00
|
|
|
return m_mutex;
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
Q_DISABLE_COPY(QMutexLocker)
|
|
|
|
|
2022-03-06 13:29:54 +00:00
|
|
|
Mutex *m_mutex;
|
|
|
|
bool m_isLocked = false;
|
2011-04-27 10:05:43 +00:00
|
|
|
};
|
|
|
|
|
2016-12-29 16:11:24 +00:00
|
|
|
#else // !QT_CONFIG(thread) && !Q_CLANG_QDOC
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
class QMutex
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2021-04-14 14:24:44 +00:00
|
|
|
constexpr QMutex() noexcept { }
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2019-04-02 08:54:54 +00:00
|
|
|
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 {}
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2016-07-14 14:37:55 +00:00
|
|
|
template <class Rep, class Period>
|
2019-04-02 08:54:54 +00:00
|
|
|
inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept
|
2016-07-14 14:37:55 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(duration);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<class Clock, class Duration>
|
2019-04-02 08:54:54 +00:00
|
|
|
inline bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) noexcept
|
2016-07-14 14:37:55 +00:00
|
|
|
{
|
|
|
|
Q_UNUSED(timePoint);
|
|
|
|
return true;
|
|
|
|
}
|
2021-06-30 13:38:41 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
Q_DISABLE_COPY(QMutex)
|
2011-04-27 10:05:43 +00:00
|
|
|
};
|
|
|
|
|
2019-06-26 21:41:40 +00:00
|
|
|
class QRecursiveMutex : public QMutex {};
|
|
|
|
|
2020-09-04 13:35:16 +00:00
|
|
|
template <typename Mutex>
|
2021-09-18 09:29:23 +00:00
|
|
|
class [[nodiscard]] QMutexLocker
|
2011-04-27 10:05:43 +00:00
|
|
|
{
|
|
|
|
public:
|
2020-09-04 08:41:56 +00:00
|
|
|
inline explicit QMutexLocker(Mutex *) noexcept {}
|
2019-04-02 08:54:54 +00:00
|
|
|
inline ~QMutexLocker() noexcept {}
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2019-04-02 08:54:54 +00:00
|
|
|
inline void unlock() noexcept {}
|
|
|
|
void relock() noexcept {}
|
2020-09-04 08:41:56 +00:00
|
|
|
inline Mutex *mutex() const noexcept { return nullptr; }
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
Q_DISABLE_COPY(QMutexLocker)
|
|
|
|
};
|
|
|
|
|
2011-07-02 13:13:12 +00:00
|
|
|
typedef QMutex QBasicMutex;
|
|
|
|
|
2016-12-29 16:11:24 +00:00
|
|
|
#endif // !QT_CONFIG(thread) && !Q_CLANG_QDOC
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
|
|
|
#endif // QMUTEX_H
|