diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2016-07-14 15:37:55 +0100 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2016-07-25 13:10:07 +0000 |
commit | a594f85d542377d604f8287e7e7bec8fa9896265 (patch) | |
tree | c17ce56923e173d03f52a868bb46a95287e5cba0 /src | |
parent | a8cf3b02576d987970dbc1cc2a11e0fb1fc1cf86 (diff) |
Q(Basic)Mutex: add try_lock{,_for,_until} for STL compatibility
Now QBasicMutex is Lockable and QMutex is TimedLockable, which means they can
be used in std::lock_guard, std::unique_lock, std::lock, etc.
[ChangeLog][QtCore][QMutex] QMutex now fully models the TimedLockable
concept by providing the try_lock, try_lock_for and try_lock_until
functions, therefore making it usable in Standard Library lock
management classes and functions.
Change-Id: I7c691481a5781a696701e1ab78186b5cefbd6a87
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/thread/qmutex.cpp | 55 | ||||
-rw-r--r-- | src/corelib/thread/qmutex.h | 57 |
2 files changed, 112 insertions, 0 deletions
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 0b14ec31c2..6dfe1ddc89 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -264,6 +264,61 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT return lockInternal(timeout); } +/*! \fn bool QMutex::try_lock() + \since 5.8 + + This function is provided for compatibility with the Standard Library + concept \c Lockable. It is equivalent to tryLock(). +*/ + +/*! \fn bool QMutex::try_lock_for(std::chrono::duration<Rep, Period> duration) + \since 5.8 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait for at most \a duration + for the mutex to become available. + + Note: Passing a negative duration as the \a duration is equivalent to + calling try_lock(). This behavior is different from tryLock. + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread is allowed if this mutex is a + \l{QMutex::Recursive}{recursive mutex}. If this mutex is a + \l{QMutex::NonRecursive}{non-recursive mutex}, this function will + \e always return false when attempting to lock the mutex + recursively. + + \sa lock(), unlock() +*/ + +/*! \fn bool QMutex::try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) + \since 5.8 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait at most until \a timePoint + for the mutex to become available. + + Note: Passing a \a timePoint which has already passed is equivalent + to calling try_lock. This behavior is different from tryLock. + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread is allowed if this mutex is a + \l{QMutex::Recursive}{recursive mutex}. If this mutex is a + \l{QMutex::NonRecursive}{non-recursive mutex}, this function will + \e always return false when attempting to lock the mutex + recursively. + + \sa lock(), unlock() +*/ + /*! \fn void QMutex::unlock() Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index a06bcd99ac..da8d1704b0 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -44,6 +44,10 @@ #include <QtCore/qatomic.h> #include <new> +#if QT_HAS_INCLUDE(<chrono>) +# include <chrono> +#endif + QT_BEGIN_NAMESPACE @@ -60,11 +64,13 @@ class QMutexData; class Q_CORE_EXPORT QBasicMutex { public: + // BasicLockable concept inline void lock() QT_MUTEX_LOCK_NOEXCEPT { if (!fastTryLock()) lockInternal(); } + // BasicLockable concept inline void unlock() Q_DECL_NOTHROW { Q_ASSERT(d_ptr.load()); //mutex must be locked if (!fastTryUnlock()) @@ -75,6 +81,9 @@ public: return fastTryLock(); } + // Lockable concept + bool try_lock() Q_DECL_NOTHROW { return tryLock(); } + bool isRecursive() Q_DECL_NOTHROW; //### Qt6: remove me bool isRecursive() const Q_DECL_NOTHROW; @@ -112,10 +121,41 @@ public: explicit QMutex(RecursionMode mode = NonRecursive); ~QMutex(); + // BasicLockable concept void lock() QT_MUTEX_LOCK_NOEXCEPT; bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; + // BasicLockable concept void unlock() Q_DECL_NOTHROW; + // Lockable concept + bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } + +#if QT_HAS_INCLUDE(<chrono>) + // TimedLockable concept + template <class Rep, class Period> + bool try_lock_for(std::chrono::duration<Rep, Period> duration) + { + // § 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 tryLock(0); + return tryLock(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()); + } + + // 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 § 30.4.1.3.12 [thread.timedmutex.requirements] + + return try_lock_for(timePoint - Clock::now()); + } +#endif + bool isRecursive() const Q_DECL_NOTHROW { return QBasicMutex::isRecursive(); } @@ -189,9 +229,26 @@ public: inline void lock() Q_DECL_NOTHROW {} inline bool tryLock(int timeout = 0) Q_DECL_NOTHROW { Q_UNUSED(timeout); return true; } + inline bool try_lock() Q_DECL_NOTHROW { return true; } inline void unlock() Q_DECL_NOTHROW {} inline bool isRecursive() const Q_DECL_NOTHROW { return true; } +#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC) + template <class Rep, class Period> + inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) Q_DECL_NOTHROW + { + Q_UNUSED(duration); + return true; + } + + template<class Clock, class Duration> + inline bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) Q_DECL_NOTHROW + { + Q_UNUSED(timePoint); + return true; + } +#endif + private: Q_DISABLE_COPY(QMutex) }; |