diff options
-rw-r--r-- | src/concurrent/qtconcurrentthreadengine.cpp | 10 | ||||
-rw-r--r-- | src/concurrent/qtconcurrentthreadengine.h | 11 | ||||
-rw-r--r-- | src/corelib/thread/qfuture.h | 29 | ||||
-rw-r--r-- | src/corelib/thread/qfuture.qdoc | 116 | ||||
-rw-r--r-- | src/corelib/thread/qfutureinterface.cpp | 60 | ||||
-rw-r--r-- | src/corelib/thread/qfutureinterface.h | 32 | ||||
-rw-r--r-- | src/corelib/thread/qfutureinterface_p.h | 6 | ||||
-rw-r--r-- | src/corelib/thread/qfuturewatcher.cpp | 171 | ||||
-rw-r--r-- | src/corelib/thread/qfuturewatcher.h | 39 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qfuture/tst_qfuture.cpp | 106 | ||||
-rw-r--r-- | tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp | 175 |
11 files changed, 622 insertions, 133 deletions
diff --git a/src/concurrent/qtconcurrentthreadengine.cpp b/src/concurrent/qtconcurrentthreadengine.cpp index 7ea606f60b..2c6e052621 100644 --- a/src/concurrent/qtconcurrentthreadengine.cpp +++ b/src/concurrent/qtconcurrentthreadengine.cpp @@ -219,9 +219,9 @@ void ThreadEngineBase::acquireBarrierSemaphore() barrier.acquire(); } -void ThreadEngineBase::reportIfPausedDone() const +void ThreadEngineBase::reportIfSuspensionDone() const { - if (futureInterface && futureInterface->isPaused()) + if (futureInterface && futureInterface->isSuspending()) futureInterface->reportSuspended(); } @@ -313,11 +313,11 @@ void ThreadEngineBase::run() // implements QRunnable. if (threadThrottleExit()) { return; } else { - // If the last worker thread is throttled and the state is paused, - // it means that pause has been requested, and it is already + // If the last worker thread is throttled and the state is "suspending", + // it means that suspension has been requested, and it is already // in effect (because all previous threads have already exited). // Report the "Suspended" state. - reportIfPausedDone(); + reportIfSuspensionDone(); } } diff --git a/src/concurrent/qtconcurrentthreadengine.h b/src/concurrent/qtconcurrentthreadengine.h index 4e7e8d0b81..82bff5fb3a 100644 --- a/src/concurrent/qtconcurrentthreadengine.h +++ b/src/concurrent/qtconcurrentthreadengine.h @@ -99,14 +99,19 @@ public: void setProgressValue(int progress); void setProgressRange(int minimum, int maximum); void acquireBarrierSemaphore(); - void reportIfPausedDone() const; + void reportIfSuspensionDone() const; protected: // The user overrides these: virtual void start() {} virtual void finish() {} virtual ThreadFunctionResult threadFunction() { return ThreadFinished; } - virtual bool shouldStartThread() { return futureInterface ? !futureInterface->isPaused() : true; } - virtual bool shouldThrottleThread() { return futureInterface ? futureInterface->isPaused() : false; } + virtual bool shouldStartThread() { return !shouldThrottleThread(); } + virtual bool shouldThrottleThread() + { + return futureInterface ? (futureInterface->isSuspending() || futureInterface->isSuspended()) + : false; + } + private: bool startThreadInternal(); void startThreads(); diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h index 4f9ba0bd6b..dc8e0d1d2d 100644 --- a/src/corelib/thread/qfuture.h +++ b/src/corelib/thread/qfuture.h @@ -109,12 +109,31 @@ public: void cancel() { d.cancel(); } bool isCanceled() const { return d.isCanceled(); } - void setPaused(bool paused) { d.setPaused(paused); } - bool isPaused() const { return d.isPaused(); } +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.") + void setPaused(bool paused) { d.setSuspended(paused); } + + QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.") + bool isPaused() const + { +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + return d.isPaused(); +QT_WARNING_POP + } + + QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.") + void togglePaused() { d.toggleSuspended(); } + + QT_DEPRECATED_VERSION_X_6_0("Use suspend() instead.") + void pause() { suspend(); } +#endif + bool isSuspending() const { return d.isSuspending(); } bool isSuspended() const { return d.isSuspended(); } - void pause() { setPaused(true); } - void resume() { setPaused(false); } - void togglePaused() { d.togglePaused(); } + void setSuspended(bool suspend) { d.setSuspended(suspend); } + void suspend() { setSuspended(true); } + void resume() { setSuspended(false); } + void toggleSuspended() { d.toggleSuspended(); } bool isStarted() const { return d.isStarted(); } bool isFinished() const { return d.isFinished(); } diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index dd55c3377b..b20875c423 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -104,11 +104,11 @@ QFuture also offers ways to interact with a runnning computation. For instance, the computation can be canceled with the cancel() function. To - pause the computation, use the setPaused() function or one of the pause(), - resume(), or togglePaused() convenience functions. Be aware that not all - running asynchronous computations can be canceled or paused. For example, - the future returned by QtConcurrent::run() cannot be canceled; but the - future returned by QtConcurrent::mappedReduced() can. + suspend or resume the computation, use the setSuspended() function or one of + the suspend(), resume(), or toggleSuspended() convenience functions. Be aware + that not all running asynchronous computations can be canceled or suspended. + For example, the future returned by QtConcurrent::run() cannot be canceled; + but the future returned by QtConcurrent::mappedReduced() can. Progress information is provided by the progressValue(), progressMinimum(), progressMaximum(), and progressText() functions. The @@ -116,7 +116,7 @@ the computation to finish, ensuring that all results are available. The state of the computation represented by a QFuture can be queried using - the isCanceled(), isStarted(), isFinished(), isRunning(), isPaused() + the isCanceled(), isStarted(), isFinished(), isRunning(), isSuspending() or isSuspended() functions. QFuture is a lightweight reference counted class that can be passed by @@ -204,8 +204,13 @@ function returns \c true. See cancel() for more details. */ + +#if QT_DEPRECATED_SINCE(6, 0) /*! \fn template <typename T> void QFuture<T>::setPaused(bool paused) + \obsolete + Use setSuspended() instead. + If \a paused is true, this function pauses the asynchronous computation represented by the future. If the computation is already paused, this function does nothing. Any QFutureWatcher object that is watching this @@ -225,6 +230,9 @@ /*! \fn template <typename T> bool QFuture<T>::isPaused() const + \obsolete + Use isSuspending() or isSuspended() instead. + Returns \c true if the asynchronous computation has been paused with the pause() function; otherwise returns \c false. @@ -235,38 +243,104 @@ \sa setPaused(), togglePaused(), isSuspended() */ +/*! \fn template <typename T> void QFuture<T>::pause() + + \obsolete + Use suspend() instead. + + Pauses the asynchronous computation represented by this future. This is a + convenience method that simply calls setPaused(true). + + \sa resume() +*/ + +/*! \fn template <typename T> void QFuture<T>::togglePaused() + + \obsolete + Use toggleSuspended() instead. + + Toggles the paused state of the asynchronous computation. In other words, + if the computation is currently paused, calling this function resumes it; + if the computation is running, it is paused. This is a convenience method + for calling setPaused(!isPaused()). + + \sa setPaused(), pause(), resume() +*/ +#endif // QT_DEPRECATED_SINCE(6, 0) + +/*! \fn template <typename T> void QFuture<T>::setSuspended(bool suspend) + + \since 6.0 + + If \a suspend is true, this function suspends the asynchronous computation + represented by the future(). If the computation is already suspended, this + function does nothing. QFutureWatcher will not immediately stop delivering + progress and result ready signals when the future is suspended. At the moment + of suspending there may still be computations that are in progress and cannot + be stopped. Signals for such computations will still be delivered. + + If \a suspend is false, this function resumes the asynchronous computation. + If the computation was not previously suspended, this function does nothing. + + Be aware that not all computations can be suspended. For example, the + QFuture returned by QtConcurrent::run() cannot be suspended; but the QFuture + returned by QtConcurrent::mappedReduced() can. + + \sa suspend(), resume(), toggleSuspended() +*/ + +/*! \fn template <typename T> bool QFuture<T>::isSuspending() const + + \since 6.0 + + Returns \c true if the asynchronous computation has been suspended with the + suspend() function, but the work is not yet suspended, and computation is still + running. Returns \c false otherwise. + + To check if suspension is actually in effect, use isSuspended() instead. + + \sa setSuspended(), toggleSuspended(), isSuspended() +*/ + /*! \fn template <typename T> bool QFuture<T>::isSuspended() const - Returns \c true if a paused asynchronous computation has been suspended, - and no more results or progress changes are expected. + \since 6.0 + + Returns \c true if a suspension of the asynchronous computation has been + requested, and it is in effect, meaning that no more results or progress + changes are expected. - \sa setPaused(), togglePaused(), isPaused() + \sa setSuspended(), toggleSuspended(), isSuspending() */ -/*! \fn template <typename T> void QFuture<T>::pause() +/*! \fn template <typename T> void QFuture<T>::suspend() - Pauses the asynchronous computation represented by this future. This is a - convenience method that simply calls setPaused(true). + \since 6.0 + + Suspends the asynchronous computation represented by this future. This is a + convenience method that simply calls setSuspended(true). \sa resume() */ /*! \fn template <typename T> void QFuture<T>::resume() - Resumes the asynchronous computation represented by this future. This is a - convenience method that simply calls setPaused(false). + Resumes the asynchronous computation represented by the future(). This is + a convenience method that simply calls setSuspended(false). - \sa pause() + \sa suspend() */ -/*! \fn template <typename T> void QFuture<T>::togglePaused() +/*! \fn template <typename T> void QFuture<T>::toggleSuspended() - Toggles the paused state of the asynchronous computation. In other words, - if the computation is currently paused, calling this function resumes it; - if the computation is running, it is paused. This is a convenience method - for calling setPaused(!isPaused()). + \since 6.0 - \sa setPaused(), pause(), resume() + Toggles the suspended state of the asynchronous computation. In other words, + if the computation is currently suspending or suspended, calling this + function resumes it; if the computation is running, it is suspended. This is a + convenience method for calling setSuspended(!(isSuspending() || isSuspended())). + + \sa setSuspended(), suspend(), resume() */ /*! \fn template <typename T> bool QFuture<T>::isStarted() const diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp index 1d8e4ac1a4..05482c40c2 100644 --- a/src/corelib/thread/qfutureinterface.cpp +++ b/src/corelib/thread/qfutureinterface.cpp @@ -65,6 +65,10 @@ public: ~ThreadPoolThreadReleaser() { if (m_pool) m_pool->reserveThread(); } }; + +const auto suspendingOrSuspended = + QFutureInterfaceBase::Suspending | QFutureInterfaceBase::Suspended; + } // unnamed namespace @@ -110,36 +114,36 @@ void QFutureInterfaceBase::cancel() if (d->state.loadRelaxed() & Canceled) return; - switch_from_to(d->state, Paused | Suspended, Canceled); + switch_from_to(d->state, suspendingOrSuspended, Canceled); d->waitCondition.wakeAll(); d->pausedWaitCondition.wakeAll(); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); d->isValid = false; } -void QFutureInterfaceBase::setPaused(bool paused) +void QFutureInterfaceBase::setSuspended(bool suspend) { QMutexLocker locker(&d->m_mutex); - if (paused) { - switch_on(d->state, Paused); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + if (suspend) { + switch_on(d->state, Suspending); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspending)); } else { - switch_off(d->state, Paused | Suspended); + switch_off(d->state, suspendingOrSuspended); d->pausedWaitCondition.wakeAll(); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); } } -void QFutureInterfaceBase::togglePaused() +void QFutureInterfaceBase::toggleSuspended() { QMutexLocker locker(&d->m_mutex); - if (d->state.loadRelaxed() & Paused) { - switch_off(d->state, Paused | Suspended); + if (d->state.loadRelaxed() & suspendingOrSuspended) { + switch_off(d->state, suspendingOrSuspended); d->pausedWaitCondition.wakeAll(); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); } else { - switch_on(d->state, Paused); - d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + switch_on(d->state, Suspending); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspending)); } } @@ -150,10 +154,10 @@ void QFutureInterfaceBase::reportSuspended() const QMutexLocker locker(&d->m_mutex); const int state = d->state; - if (!(state & Paused) || (state & Suspended)) + if (!(state & Suspending) || (state & Suspended)) return; - switch_on(d->state, Suspended); + switch_from_to(d->state, Suspending, Suspended); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspended)); } @@ -164,7 +168,7 @@ void QFutureInterfaceBase::setThrottled(bool enable) switch_on(d->state, Throttled); } else { switch_off(d->state, Throttled); - if (!(d->state.loadRelaxed() & Paused)) + if (!(d->state.loadRelaxed() & suspendingOrSuspended)) d->pausedWaitCondition.wakeAll(); } } @@ -190,10 +194,17 @@ bool QFutureInterfaceBase::isFinished() const return queryState(Finished); } +bool QFutureInterfaceBase::isSuspending() const +{ + return queryState(Suspending); +} + +#if QT_DEPRECATED_SINCE(6, 0) bool QFutureInterfaceBase::isPaused() const { - return queryState(Paused); + return queryState(static_cast<State>(suspendingOrSuspended)); } +#endif bool QFutureInterfaceBase::isSuspended() const { @@ -233,13 +244,13 @@ void QFutureInterfaceBase::waitForResume() // return early if possible to avoid taking the mutex lock. { const int state = d->state.loadRelaxed(); - if (!(state & Paused) || (state & Canceled)) + if (!(state & suspendingOrSuspended) || (state & Canceled)) return; } QMutexLocker lock(&d->m_mutex); const int state = d->state.loadRelaxed(); - if (!(state & Paused) || (state & Canceled)) + if (!(state & suspendingOrSuspended) || (state & Canceled)) return; // decrease active thread count since this thread will wait. @@ -576,7 +587,7 @@ void QFutureInterfaceBasePrivate::internal_setThrottled(bool enable) switch_on(state, QFutureInterfaceBase::Throttled); } else { switch_off(state, QFutureInterfaceBase::Throttled); - if (!(state.loadRelaxed() & QFutureInterfaceBase::Paused)) + if (!(state.loadRelaxed() & suspendingOrSuspended)) pausedWaitCondition.wakeAll(); } } @@ -611,7 +622,8 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface { QMutexLocker locker(&m_mutex); - if (state.loadRelaxed() & QFutureInterfaceBase::Started) { + const auto currentState = state.loadRelaxed(); + if (currentState & QFutureInterfaceBase::Started) { interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started)); interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, m_progressMinimum, @@ -631,15 +643,15 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface it.batchedAdvance(); } - if (state.loadRelaxed() & QFutureInterfaceBase::Suspended) + if (currentState & QFutureInterfaceBase::Suspended) interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspended)); - else if (state.loadRelaxed() & QFutureInterfaceBase::Paused) - interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + else if (currentState & QFutureInterfaceBase::Suspending) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspending)); - if (state.loadRelaxed() & QFutureInterfaceBase::Canceled) + if (currentState & QFutureInterfaceBase::Canceled) interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); - if (state.loadRelaxed() & QFutureInterfaceBase::Finished) + if (currentState & QFutureInterfaceBase::Finished) interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); outputConnections.append(interface); diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index ce8985f866..c802be762b 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -77,16 +77,16 @@ class Q_CORE_EXPORT QFutureInterfaceBase { public: enum State { - NoState = 0x00, - Running = 0x01, - Started = 0x02, - Finished = 0x04, - Canceled = 0x08, - Paused = 0x10, - Throttled = 0x20, + NoState = 0x00, + Running = 0x01, + Started = 0x02, + Finished = 0x04, + Canceled = 0x08, + Suspending = 0x10, + Suspended = 0x20, + Throttled = 0x40, // Pending means that the future depends on another one, which is not finished yet - Pending = 0x40, - Suspended = 0x80 + Pending = 0x80, }; QFutureInterfaceBase(State initialState = NoState); @@ -125,15 +125,25 @@ public: bool isStarted() const; bool isCanceled() const; bool isFinished() const; +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.") bool isPaused() const; + + QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.") + void setPaused(bool paused) { setSuspended(paused); } + + QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.") + void togglePaused() { toggleSuspended(); } +#endif + bool isSuspending() const; bool isSuspended() const; bool isThrottled() const; bool isResultReadyAt(int index) const; bool isValid() const; void cancel(); - void setPaused(bool paused); - void togglePaused(); + void setSuspended(bool suspend); + void toggleSuspended(); void reportSuspended() const; void setThrottled(bool enable); diff --git a/src/corelib/thread/qfutureinterface_p.h b/src/corelib/thread/qfutureinterface_p.h index 86160e8532..8ef27044bf 100644 --- a/src/corelib/thread/qfutureinterface_p.h +++ b/src/corelib/thread/qfutureinterface_p.h @@ -70,12 +70,12 @@ public: Started, Finished, Canceled, - Paused, + Suspending, + Suspended, Resumed, Progress, ProgressRange, - ResultsReady, - Suspended + ResultsReady }; QFutureCallOutEvent() diff --git a/src/corelib/thread/qfuturewatcher.cpp b/src/corelib/thread/qfuturewatcher.cpp index 12469d4884..75f5e297e2 100644 --- a/src/corelib/thread/qfuturewatcher.cpp +++ b/src/corelib/thread/qfuturewatcher.cpp @@ -64,12 +64,12 @@ QT_BEGIN_NAMESPACE For convenience, several of QFuture's functions are also available in QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(), progressText(), isStarted(), isFinished(), isRunning(), isCanceled(), - isPaused(), waitForFinished(), result(), and resultAt(). The cancel(), - setPaused(), pause(), resume(), and togglePaused() functions are slots in - QFutureWatcher. + isSuspending(), isSuspended(), waitForFinished(), result(), and resultAt(). + The cancel(), setSuspended(), suspend(), resume(), and toggleSuspended() functions + are slots in QFutureWatcher. Status changes are reported via the started(), finished(), canceled(), - paused(), resumed(), suspended(), resultReadyAt(), and resultsReadyAt() + suspending(), suspended(), resumed(), resultReadyAt(), and resultsReadyAt() signals. Progress information is provided from the progressRangeChanged(), void progressValueChanged(), and progressTextChanged() signals. @@ -85,7 +85,7 @@ QT_BEGIN_NAMESPACE \snippet code/src_corelib_thread_qfuturewatcher.cpp 0 Be aware that not all running asynchronous computations can be canceled or - paused. For example, the future returned by QtConcurrent::run() cannot be + suspended. For example, the future returned by QtConcurrent::run() cannot be canceled; but the future returned by QtConcurrent::mappedReduced() can. QFutureWatcher<void> is specialized to not contain any of the result @@ -133,8 +133,12 @@ void QFutureWatcherBase::cancel() futureInterface().cancel(); } +#if QT_DEPRECATED_SINCE(6, 0) /*! \fn template <typename T> void QFutureWatcher<T>::setPaused(bool paused) + \obsolete + Use setSuspended() instead. + If \a paused is true, this function pauses the asynchronous computation represented by the future(). If the computation is already paused, this function does nothing. QFutureWatcher will not immediately stop delivering @@ -154,11 +158,14 @@ void QFutureWatcherBase::cancel() */ void QFutureWatcherBase::setPaused(bool paused) { - futureInterface().setPaused(paused); + futureInterface().setSuspended(paused); } /*! \fn template <typename T> void QFutureWatcher<T>::pause() + \obsolete + Use suspend() instead. + Pauses the asynchronous computation represented by the future(). This is a convenience method that simply calls setPaused(true). @@ -166,33 +173,96 @@ void QFutureWatcherBase::setPaused(bool paused) */ void QFutureWatcherBase::pause() { - futureInterface().setPaused(true); + futureInterface().setSuspended(true); +} + +#endif // QT_DEPRECATED_SINCE(6, 0) + +/*! \fn template <typename T> void QFutureWatcher<T>::setSuspended(bool suspend) + + \since 6.0 + + If \a suspend is true, this function suspends the asynchronous computation + represented by the future(). If the computation is already suspended, this + function does nothing. QFutureWatcher will not immediately stop delivering + progress and result ready signals when the future is suspended. At the moment + of suspending there may still be computations that are in progress and cannot + be stopped. Signals for such computations will still be delivered. + + If \a suspend is false, this function resumes the asynchronous computation. + If the computation was not previously suspended, this function does nothing. + + Be aware that not all computations can be suspended. For example, the + QFuture returned by QtConcurrent::run() cannot be suspended; but the QFuture + returned by QtConcurrent::mappedReduced() can. + + \sa suspend(), resume(), toggleSuspended() +*/ +void QFutureWatcherBase::setSuspended(bool suspend) +{ + futureInterface().setSuspended(suspend); +} + +/*! \fn template <typename T> void QFutureWatcher<T>::suspend() + + \since 6.0 + + Suspends the asynchronous computation represented by this future. This is a + convenience method that simply calls setSuspended(true). + + \sa resume() +*/ +void QFutureWatcherBase::suspend() +{ + futureInterface().setSuspended(true); } /*! \fn template <typename T> void QFutureWatcher<T>::resume() Resumes the asynchronous computation represented by the future(). This is - a convenience method that simply calls setPaused(false). + a convenience method that simply calls setSuspended(false). - \sa pause() + \sa suspend() */ + void QFutureWatcherBase::resume() { - futureInterface().setPaused(false); + futureInterface().setSuspended(false); } +#if QT_DEPRECATED_SINCE(6, 0) /*! \fn template <typename T> void QFutureWatcher<T>::togglePaused() + \obsolete + Use toggleSuspended() instead. + Toggles the paused state of the asynchronous computation. In other words, if the computation is currently paused, calling this function resumes it; - if the computation is running, it becomes paused. This is a convenience - method for calling setPaused(!isPaused()). + if the computation is running, it is paused. This is a convenience method + for calling setPaused(!isPaused()). \sa setPaused(), pause(), resume() */ void QFutureWatcherBase::togglePaused() { - futureInterface().togglePaused(); + futureInterface().toggleSuspended(); +} +#endif // QT_DEPRECATED_SINCE(6, 0) + +/*! \fn template <typename T> void QFutureWatcher<T>::toggleSuspended() + + \since 6.0 + + Toggles the suspended state of the asynchronous computation. In other words, + if the computation is currently suspending or suspended, calling this + function resumes it; if the computation is running, it is suspended. This is a + convenience method for calling setSuspended(!(isSuspending() || isSuspended())). + + \sa setSuspended(), suspend(), resume() +*/ +void QFutureWatcherBase::toggleSuspended() +{ + futureInterface().toggleSuspended(); } /*! \fn template <typename T> int QFutureWatcher<T>::progressValue() const @@ -286,8 +356,13 @@ bool QFutureWatcherBase::isCanceled() const return futureInterface().queryState(QFutureInterfaceBase::Canceled); } +#if QT_DEPRECATED_SINCE(6, 0) + /*! \fn template <typename T> bool QFutureWatcher<T>::isPaused() const + \obsolete + Use isSuspending() or isSuspended() instead. + Returns \c true if the asynchronous computation has been paused with the pause() function; otherwise returns \c false. @@ -297,17 +372,42 @@ bool QFutureWatcherBase::isCanceled() const \sa setPaused(), togglePaused(), isSuspended() */ + bool QFutureWatcherBase::isPaused() const { - return futureInterface().queryState(QFutureInterfaceBase::Paused); +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + return futureInterface().isPaused(); +QT_WARNING_POP +} +#endif // QT_DEPRECATED_SINCE(6, 0) + +/*! \fn template <typename T> bool QFutureWatcher<T>::isSuspending() const + + \since 6.0 + + Returns \c true if the asynchronous computation has been suspended with the + suspend() function, but the work is not yet suspended, and computation is still + running. Returns \c false otherwise. + + To check if suspension is actually in effect, use isSuspended() instead. + + \sa setSuspended(), toggleSuspended(), isSuspended() +*/ +bool QFutureWatcherBase::isSuspending() const +{ + return futureInterface().isSuspending(); } /*! \fn template <typename T> bool QFutureWatcher<T>::isSuspended() const - Returns \c true if a paused asynchronous computation has been suspended, - and no more results or progress changes are expected. + \since 6.0 + + Returns \c true if a suspension of the asynchronous computation has been + requested, and it is in effect, meaning that no more results or progress + changes are expected. - \sa suspended(), paused(), isPaused() + \sa suspended(), setSuspended(), isSuspending() */ bool QFutureWatcherBase::isSuspended() const { @@ -439,10 +539,16 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) pendingResultsReady.storeRelaxed(0); emit q->canceled(); break; - case QFutureCallOutEvent::Paused: + case QFutureCallOutEvent::Suspending: if (q->futureInterface().isCanceled()) break; + emit q->suspending(); +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED emit q->paused(); +QT_WARNING_POP +#endif break; case QFutureCallOutEvent::Suspended: if (q->futureInterface().isCanceled()) @@ -540,7 +646,28 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) This signal is emitted if the watched future is canceled. */ +/*! \fn template <typename T> void QFutureWatcher<T>::suspending() + + \since 6.0 + + This signal is emitted when the state of the watched future is + set to suspended. + + \note This signal only informs that suspension has been requested. It + doesn't indicate that all background operations are stopped. Signals + for computations that were in progress at the moment of suspending will + still be delivered. To be informed when suspension actually + took effect, use the suspended() signal. + + \sa setSuspended(), suspend(), suspended() +*/ + +#if QT_DEPRECATED_SINCE(6, 0) /*! \fn template <typename T> void QFutureWatcher<T>::paused() + + \obsolete + Use suspending() instead. + This signal is emitted when the state of the watched future is set to paused. @@ -552,13 +679,17 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) \sa setPaused(), pause(), suspended() */ +#endif // QT_DEPRECATED_SINCE(6, 0) /*! \fn template <typename T> void QFutureWatcher<T>::suspended() - This signal is emitted when pause() took effect, meaning that there are + + \since 6.0 + + This signal is emitted when suspend() took effect, meaning that there are no more running computations. After receiving this signal no more result ready or progress reporting signals are expected. - \sa setPaused(), pause(), paused() + \sa setSuspended(), suspend(), suspended() */ /*! \fn template <typename T> void QFutureWatcher<T>::resumed() diff --git a/src/corelib/thread/qfuturewatcher.h b/src/corelib/thread/qfuturewatcher.h index 0c8c1ec247..d2b8eeace1 100644 --- a/src/corelib/thread/qfuturewatcher.h +++ b/src/corelib/thread/qfuturewatcher.h @@ -69,7 +69,11 @@ public: bool isFinished() const; bool isRunning() const; bool isCanceled() const; +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.") bool isPaused() const; +#endif + bool isSuspending() const; bool isSuspended() const; void waitForFinished(); @@ -82,7 +86,11 @@ Q_SIGNALS: void started(); void finished(); void canceled(); +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use suspending() instead.") void paused(); +#endif + void suspending(); void suspended(); void resumed(); void resultReadyAt(int resultIndex); @@ -93,10 +101,21 @@ Q_SIGNALS: public Q_SLOTS: void cancel(); + void setSuspended(bool suspend); + void suspend(); + void resume(); + void toggleSuspended(); + +#if QT_DEPRECATED_SINCE(6, 0) + QT_DEPRECATED_VERSION_X_6_0("Use setSuspended() instead.") void setPaused(bool paused); + + QT_DEPRECATED_VERSION_X_6_0("Use suspended() instead.") void pause(); - void resume(); + + QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.") void togglePaused(); +#endif protected: void connectNotify (const QMetaMethod &signal) override; @@ -148,8 +167,11 @@ public: bool isFinished() const; bool isRunning() const; bool isCanceled() const; +#if QT_DEPRECATED_SINCE(6, 0) bool isPaused() const; - bool isSuspended() const +#endif + bool isSuspending() const; + bool isSuspended() const; void waitForFinished(); @@ -159,7 +181,10 @@ Q_SIGNALS: void started(); void finished(); void canceled(); +#if QT_DEPRECATED_SINCE(6, 0) void paused(); +#endif + void suspending(); void suspended(); void resumed(); void resultReadyAt(int resultIndex); @@ -170,11 +195,17 @@ Q_SIGNALS: public Q_SLOTS: void cancel(); + void setSuspended(bool suspend); + void suspend(); + void resume(); + void toggleSuspended(); +#if QT_DEPRECATED_SINCE(6, 0) void setPaused(bool paused); void pause(); - void resume(); void togglePaused(); -#endif +#endif // QT_DEPRECATED_SINCE(6, 0) + +#endif // Q_QDOC private: QFuture<T> m_future; diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp index d647ce6eba..7a94908f6b 100644 --- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp +++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp @@ -112,7 +112,10 @@ private slots: void implicitConversions(); void iterators(); void iteratorsThread(); +#if QT_DEPRECATED_SINCE(6, 0) void pause(); + void suspendCheckPaused(); +#endif void suspend(); void throttling(); void voidConversions(); @@ -1315,6 +1318,9 @@ public: QSet<int> reportedProgress; }; +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED void tst_QFuture::pause() { QFutureInterface<void> Interface; @@ -1335,39 +1341,98 @@ void tst_QFuture::pause() Interface.reportFinished(); } +void tst_QFuture::suspendCheckPaused() +{ + QFutureInterface<void> interface; + + interface.reportStarted(); + QFuture<void> f = interface.future(); + QVERIFY(!f.isSuspended()); + + interface.reportSuspended(); + QVERIFY(!f.isSuspended()); + + f.pause(); + QVERIFY(!f.isSuspended()); + QVERIFY(f.isPaused()); + + // resume when still pausing + f.resume(); + QVERIFY(!f.isSuspended()); + QVERIFY(!f.isPaused()); + + // pause again + f.pause(); + QVERIFY(!f.isSuspended()); + QVERIFY(f.isPaused()); + + interface.reportSuspended(); + QVERIFY(f.isSuspended()); + QVERIFY(f.isPaused()); + + // resume after suspended + f.resume(); + QVERIFY(!f.isSuspended()); + QVERIFY(!f.isPaused()); + + // pause again and cancel + f.pause(); + interface.reportSuspended(); + + interface.reportCanceled(); + QVERIFY(!f.isSuspended()); + QVERIFY(!f.isPaused()); + QVERIFY(f.isCanceled()); + + interface.reportFinished(); +} + +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 0) + void tst_QFuture::suspend() { QFutureInterface<void> interface; interface.reportStarted(); QFuture<void> f = interface.future(); - QVERIFY(!interface.isSuspended()); + QVERIFY(!f.isSuspended()); interface.reportSuspended(); - QVERIFY(!interface.isSuspended()); + QVERIFY(!f.isSuspended()); + QVERIFY(!f.isSuspending()); + + f.suspend(); + QVERIFY(f.isSuspending()); + QVERIFY(!f.isSuspended()); + + // resume when still suspending + f.resume(); + QVERIFY(!f.isSuspending()); + QVERIFY(!f.isSuspended()); - // pause - interface.togglePaused(); - QVERIFY(!interface.isSuspended()); - QVERIFY(interface.isPaused()); + // suspend again + f.suspend(); + QVERIFY(f.isSuspending()); + QVERIFY(!f.isSuspended()); interface.reportSuspended(); - QVERIFY(interface.isSuspended()); - QVERIFY(interface.isPaused()); + QVERIFY(!f.isSuspending()); + QVERIFY(f.isSuspended()); - // resume - interface.togglePaused(); - QVERIFY(!interface.isSuspended()); - QVERIFY(!interface.isPaused()); + // resume after suspended + f.resume(); + QVERIFY(!f.isSuspending()); + QVERIFY(!f.isSuspended()); - // pause again - interface.togglePaused(); + // suspend again and cancel + f.suspend(); interface.reportSuspended(); interface.reportCanceled(); - QVERIFY(!interface.isSuspended()); - QVERIFY(!interface.isPaused()); - QVERIFY(interface.isCanceled()); + QVERIFY(!f.isSuspending()); + QVERIFY(!f.isSuspended()); + QVERIFY(f.isCanceled()); interface.reportFinished(); } @@ -2715,7 +2780,14 @@ void tst_QFuture::testFutureTaken(QFuture<T> &noMoreFuture) QCOMPARE(noMoreFuture.resultCount(), 0); QCOMPARE(noMoreFuture.isStarted(), false); QCOMPARE(noMoreFuture.isRunning(), false); + QCOMPARE(noMoreFuture.isSuspending(), false); + QCOMPARE(noMoreFuture.isSuspended(), false); +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QCOMPARE(noMoreFuture.isPaused(), false); +QT_WARNING_POP +#endif QCOMPARE(noMoreFuture.isFinished(), false); QCOMPARE(noMoreFuture.progressValue(), 0); } diff --git a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp index 13fb587607..d4f609874e 100644 --- a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp +++ b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp @@ -57,9 +57,13 @@ private slots: void sharedFutureInterface(); void changeFuture(); void cancelEvents(); +#if QT_DEPRECATED_SINCE(6, 0) void pauseEvents(); + void pausedSuspendedOrder(); +#endif + void suspendEvents(); void suspended(); - void suspendedEvents(); + void suspendedEventsOrder(); void finishedState(); void throttling(); void incrementalMapResults(); @@ -548,12 +552,21 @@ void callInterface(T &obj) obj.isFinished(); obj.isRunning(); obj.isCanceled(); - obj.isPaused(); + obj.isSuspended(); + obj.isSuspending(); obj.cancel(); - obj.pause(); + obj.suspend(); obj.resume(); + obj.toggleSuspended(); +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED + obj.isPaused(); + obj.pause(); obj.togglePaused(); +QT_WARNING_POP +#endif obj.waitForFinished(); const T& objConst = obj; @@ -566,7 +579,14 @@ void callInterface(T &obj) objConst.isFinished(); objConst.isRunning(); objConst.isCanceled(); + objConst.isSuspending(); + objConst.isSuspended(); +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED objConst.isPaused(); +QT_WARNING_POP +#endif } template <typename T> @@ -665,6 +685,9 @@ void tst_QFutureWatcher::cancelEvents() QCOMPARE(resultReadySpy.count(), 0); } +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED // Tests that events from paused futures are saved and // delivered on resume. void tst_QFutureWatcher::pauseEvents() @@ -725,11 +748,120 @@ void tst_QFutureWatcher::pauseEvents() } } +void tst_QFutureWatcher::pausedSuspendedOrder() +{ + QFutureInterface<void> iface; + iface.reportStarted(); + + QFutureWatcher<void> watcher; + + QSignalSpy pausedSpy(&watcher, &QFutureWatcher<void>::paused); + QVERIFY(pausedSpy.isValid()); + + QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<void>::suspended); + QVERIFY(suspendedSpy.isValid()); + + bool pausedBeforeSuspended = false; + bool notSuspendedBeforePaused = false; + connect(&watcher, &QFutureWatcher<void>::paused, + [&] { notSuspendedBeforePaused = (suspendedSpy.count() == 0); }); + connect(&watcher, &QFutureWatcher<void>::suspended, + [&] { pausedBeforeSuspended = (pausedSpy.count() == 1); }); + + watcher.setFuture(iface.future()); + iface.reportSuspended(); + + // Make sure reportPaused() is ignored if the state is not paused + pausedSpy.wait(100); + QCOMPARE(pausedSpy.count(), 0); + QCOMPARE(suspendedSpy.count(), 0); + + iface.setPaused(true); + iface.reportSuspended(); + + QTRY_COMPARE(suspendedSpy.count(), 1); + QCOMPARE(pausedSpy.count(), 1); + QVERIFY(notSuspendedBeforePaused); + QVERIFY(pausedBeforeSuspended); + + iface.reportFinished(); +} +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 0) + +// Tests that events from suspended futures are saved and +// delivered on resume. +void tst_QFutureWatcher::suspendEvents() +{ + { + QFutureInterface<int> iface; + iface.reportStarted(); + + QFutureWatcher<int> watcher; + + SignalSlotObject object; + connect(&watcher, &QFutureWatcher<int>::resultReadyAt, &object, + &SignalSlotObject::resultReadyAt); + QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt); + QVERIFY(resultReadySpy.isValid()); + + QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<int>::suspending); + QVERIFY(suspendingSpy.isValid()); + + watcher.setFuture(iface.future()); + watcher.suspend(); + + QTRY_COMPARE(suspendingSpy.count(), 1); + + int value = 0; + iface.reportFinished(&value); + + // A result is reported, although the watcher is paused. + // The corresponding event should be also reported. + QTRY_COMPARE(resultReadySpy.count(), 1); + + watcher.resume(); + } + { + QFutureInterface<int> iface; + iface.reportStarted(); + + QFuture<int> a = iface.future(); + + QFutureWatcher<int> watcher; + + SignalSlotObject object; + connect(&watcher, &QFutureWatcher<int>::resultReadyAt, &object, + &SignalSlotObject::resultReadyAt); + QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt); + QVERIFY(resultReadySpy.isValid()); + + watcher.setFuture(a); + a.suspend(); + + int value = 0; + iface.reportFinished(&value); + + QFuture<int> b; + watcher.setFuture(b); // If we watch b instead, resuming a + a.resume(); // should give us no results. + + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 0); + } +} + void tst_QFutureWatcher::suspended() { QFutureWatcher<void> watcher; QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt); +#if QT_DEPRECATED_SINCE(6, 0) +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED QSignalSpy pausedSpy(&watcher, &QFutureWatcher<int>::paused); +QT_WARNING_POP +#endif + QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<int>::suspending); QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<int>::suspended); QSignalSpy finishedSpy(&watcher, &QFutureWatcher<int>::finished); @@ -748,13 +880,16 @@ void tst_QFutureWatcher::suspended() }); watcher.setFuture(future); - // Allow some threads to start before pausing. + // Allow some threads to start before suspending. QThread::msleep(200); - watcher.pause(); - watcher.pause(); + watcher.suspend(); + watcher.suspend(); QTRY_COMPARE(suspendedSpy.count(), 1); // suspended() should be emitted only once + QCOMPARE(suspendingSpy.count(), 2); // suspending() is emitted as many times as requested +#if QT_DEPRECATED_SINCE(6, 0) QCOMPARE(pausedSpy.count(), 2); // paused() is emitted as many times as requested +#endif // Make sure QFutureWatcher::resultReadyAt() is emitted only for already started threads. const auto resultReadyAfterPaused = resultReadySpy.count(); @@ -775,41 +910,41 @@ void tst_QFutureWatcher::suspended() QCOMPARE(resultReadySpy.count(), numValues - resultReadyAfterPaused); } -void tst_QFutureWatcher::suspendedEvents() +void tst_QFutureWatcher::suspendedEventsOrder() { QFutureInterface<void> iface; iface.reportStarted(); QFutureWatcher<void> watcher; - QSignalSpy pausedSpy(&watcher, &QFutureWatcher<void>::paused); - QVERIFY(pausedSpy.isValid()); + QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<void>::suspending); + QVERIFY(suspendingSpy.isValid()); QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<void>::suspended); QVERIFY(suspendedSpy.isValid()); - bool pausedBeforeSuspended = false; - bool notSuspendedBeforePasused = false; - connect(&watcher, &QFutureWatcher<void>::paused, - [&] { notSuspendedBeforePasused = (suspendedSpy.count() == 0); }); + bool suspendingBeforeSuspended = false; + bool notSuspendedBeforeSuspending = false; + connect(&watcher, &QFutureWatcher<void>::suspending, + [&] { notSuspendedBeforeSuspending = (suspendedSpy.count() == 0); }); connect(&watcher, &QFutureWatcher<void>::suspended, - [&] { pausedBeforeSuspended = (pausedSpy.count() == 1); }); + [&] { suspendingBeforeSuspended = (suspendingSpy.count() == 1); }); watcher.setFuture(iface.future()); iface.reportSuspended(); // Make sure reportPaused() is ignored if the state is not paused - pausedSpy.wait(100); - QCOMPARE(pausedSpy.count(), 0); + suspendingSpy.wait(100); + QCOMPARE(suspendingSpy.count(), 0); QCOMPARE(suspendedSpy.count(), 0); - iface.setPaused(true); + iface.setSuspended(true); iface.reportSuspended(); QTRY_COMPARE(suspendedSpy.count(), 1); - QCOMPARE(pausedSpy.count(), 1); - QVERIFY(notSuspendedBeforePasused); - QVERIFY(pausedBeforeSuspended); + QCOMPARE(suspendingSpy.count(), 1); + QVERIFY(notSuspendedBeforeSuspending); + QVERIFY(suspendingBeforeSuspended); iface.reportFinished(); } |