Deprecate the pause-related APIs of QFuture* classes

Deprecated the pause-related APIs of QFuture* classes and
added alternatives having "suspend" in the name instead.

With 2f15927f01ceef0aca490746302a5ea57ea9441c new
isSuspended()/suspended() APIs have been added to QFuture* classes for
checking if pause/suspension is still in progress or it already took
effect. To keep the naming more consistent, renamed:

 - setPaused() -> setSuspended()
 - pause() -> suspend()
 - togglePaused() -> toggleSuspended()
 - QFutureWatcher::paused() -> QFutureWatcher::suspending()

Note that QFuture*::isPaused() now corresponds to (isSuspending() ||
isSuspended()).

[ChangeLog][Deprecation Notice] Deprecated pause-related APIs of
QFuture and QFutureWatcher. Added alternatives having "suspend" in
the name instead.

Change-Id: Ibeb75017a118401d64d18b72fb95d78e28c4661c
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
Sona Kurazyan 2020-06-02 10:48:06 +02:00
parent 036c3c19e7
commit 37cfc3c6d2
11 changed files with 624 additions and 135 deletions

View File

@ -219,9 +219,9 @@ void ThreadEngineBase::acquireBarrierSemaphore()
barrier.acquire(); barrier.acquire();
} }
void ThreadEngineBase::reportIfPausedDone() const void ThreadEngineBase::reportIfSuspensionDone() const
{ {
if (futureInterface && futureInterface->isPaused()) if (futureInterface && futureInterface->isSuspending())
futureInterface->reportSuspended(); futureInterface->reportSuspended();
} }
@ -313,11 +313,11 @@ void ThreadEngineBase::run() // implements QRunnable.
if (threadThrottleExit()) { if (threadThrottleExit()) {
return; return;
} else { } else {
// If the last worker thread is throttled and the state is paused, // If the last worker thread is throttled and the state is "suspending",
// it means that pause has been requested, and it is already // it means that suspension has been requested, and it is already
// in effect (because all previous threads have already exited). // in effect (because all previous threads have already exited).
// Report the "Suspended" state. // Report the "Suspended" state.
reportIfPausedDone(); reportIfSuspensionDone();
} }
} }

View File

@ -99,14 +99,19 @@ public:
void setProgressValue(int progress); void setProgressValue(int progress);
void setProgressRange(int minimum, int maximum); void setProgressRange(int minimum, int maximum);
void acquireBarrierSemaphore(); void acquireBarrierSemaphore();
void reportIfPausedDone() const; void reportIfSuspensionDone() const;
protected: // The user overrides these: protected: // The user overrides these:
virtual void start() {} virtual void start() {}
virtual void finish() {} virtual void finish() {}
virtual ThreadFunctionResult threadFunction() { return ThreadFinished; } virtual ThreadFunctionResult threadFunction() { return ThreadFinished; }
virtual bool shouldStartThread() { return futureInterface ? !futureInterface->isPaused() : true; } virtual bool shouldStartThread() { return !shouldThrottleThread(); }
virtual bool shouldThrottleThread() { return futureInterface ? futureInterface->isPaused() : false; } virtual bool shouldThrottleThread()
{
return futureInterface ? (futureInterface->isSuspending() || futureInterface->isSuspended())
: false;
}
private: private:
bool startThreadInternal(); bool startThreadInternal();
void startThreads(); void startThreads();

View File

@ -109,12 +109,31 @@ public:
void cancel() { d.cancel(); } void cancel() { d.cancel(); }
bool isCanceled() const { return d.isCanceled(); } bool isCanceled() const { return d.isCanceled(); }
void setPaused(bool paused) { d.setPaused(paused); } #if QT_DEPRECATED_SINCE(6, 0)
bool isPaused() const { return d.isPaused(); } 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(); } bool isSuspended() const { return d.isSuspended(); }
void pause() { setPaused(true); } void setSuspended(bool suspend) { d.setSuspended(suspend); }
void resume() { setPaused(false); } void suspend() { setSuspended(true); }
void togglePaused() { d.togglePaused(); } void resume() { setSuspended(false); }
void toggleSuspended() { d.toggleSuspended(); }
bool isStarted() const { return d.isStarted(); } bool isStarted() const { return d.isStarted(); }
bool isFinished() const { return d.isFinished(); } bool isFinished() const { return d.isFinished(); }

View File

@ -104,11 +104,11 @@
QFuture also offers ways to interact with a runnning computation. For QFuture also offers ways to interact with a runnning computation. For
instance, the computation can be canceled with the cancel() function. To instance, the computation can be canceled with the cancel() function. To
pause the computation, use the setPaused() function or one of the pause(), suspend or resume the computation, use the setSuspended() function or one of
resume(), or togglePaused() convenience functions. Be aware that not all the suspend(), resume(), or toggleSuspended() convenience functions. Be aware
running asynchronous computations can be canceled or paused. For example, that not all running asynchronous computations can be canceled or suspended.
the future returned by QtConcurrent::run() cannot be canceled; but the For example, the future returned by QtConcurrent::run() cannot be canceled;
future returned by QtConcurrent::mappedReduced() can. but the future returned by QtConcurrent::mappedReduced() can.
Progress information is provided by the progressValue(), Progress information is provided by the progressValue(),
progressMinimum(), progressMaximum(), and progressText() functions. The progressMinimum(), progressMaximum(), and progressText() functions. The
@ -116,7 +116,7 @@
the computation to finish, ensuring that all results are available. the computation to finish, ensuring that all results are available.
The state of the computation represented by a QFuture can be queried using 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. or isSuspended() functions.
QFuture is a lightweight reference counted class that can be passed by 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. 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) /*! \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 If \a paused is true, this function pauses the asynchronous computation
represented by the future. If the computation is already paused, this represented by the future. If the computation is already paused, this
function does nothing. Any QFutureWatcher object that is watching this function does nothing. Any QFutureWatcher object that is watching this
@ -225,6 +230,9 @@
/*! \fn template <typename T> bool QFuture<T>::isPaused() const /*! \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 Returns \c true if the asynchronous computation has been paused with the
pause() function; otherwise returns \c false. pause() function; otherwise returns \c false.
@ -235,32 +243,22 @@
\sa setPaused(), togglePaused(), isSuspended() \sa setPaused(), togglePaused(), 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.
\sa setPaused(), togglePaused(), isPaused()
*/
/*! \fn template <typename T> void QFuture<T>::pause() /*! \fn template <typename T> void QFuture<T>::pause()
\obsolete
Use suspend() instead.
Pauses the asynchronous computation represented by this future. This is a Pauses the asynchronous computation represented by this future. This is a
convenience method that simply calls setPaused(true). convenience method that simply calls setPaused(true).
\sa resume() \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).
\sa pause()
*/
/*! \fn template <typename T> void QFuture<T>::togglePaused() /*! \fn template <typename T> void QFuture<T>::togglePaused()
\obsolete
Use toggleSuspended() instead.
Toggles the paused state of the asynchronous computation. In other words, 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 currently paused, calling this function resumes it;
if the computation is running, it is paused. This is a convenience method if the computation is running, it is paused. This is a convenience method
@ -268,6 +266,82 @@
\sa setPaused(), pause(), resume() \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
\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 setSuspended(), toggleSuspended(), isSuspending()
*/
/*! \fn template <typename T> void QFuture<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()
*/
/*! \fn template <typename T> void QFuture<T>::resume()
Resumes the asynchronous computation represented by the future(). This is
a convenience method that simply calls setSuspended(false).
\sa suspend()
*/
/*! \fn template <typename T> void QFuture<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()
*/
/*! \fn template <typename T> bool QFuture<T>::isStarted() const /*! \fn template <typename T> bool QFuture<T>::isStarted() const

View File

@ -65,6 +65,10 @@ public:
~ThreadPoolThreadReleaser() ~ThreadPoolThreadReleaser()
{ if (m_pool) m_pool->reserveThread(); } { if (m_pool) m_pool->reserveThread(); }
}; };
const auto suspendingOrSuspended =
QFutureInterfaceBase::Suspending | QFutureInterfaceBase::Suspended;
} // unnamed namespace } // unnamed namespace
@ -110,36 +114,36 @@ void QFutureInterfaceBase::cancel()
if (d->state.loadRelaxed() & Canceled) if (d->state.loadRelaxed() & Canceled)
return; return;
switch_from_to(d->state, Paused | Suspended, Canceled); switch_from_to(d->state, suspendingOrSuspended, Canceled);
d->waitCondition.wakeAll(); d->waitCondition.wakeAll();
d->pausedWaitCondition.wakeAll(); d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
d->isValid = false; d->isValid = false;
} }
void QFutureInterfaceBase::setPaused(bool paused) void QFutureInterfaceBase::setSuspended(bool suspend)
{ {
QMutexLocker locker(&d->m_mutex); QMutexLocker locker(&d->m_mutex);
if (paused) { if (suspend) {
switch_on(d->state, Paused); switch_on(d->state, Suspending);
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspending));
} else { } else {
switch_off(d->state, Paused | Suspended); switch_off(d->state, suspendingOrSuspended);
d->pausedWaitCondition.wakeAll(); d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed));
} }
} }
void QFutureInterfaceBase::togglePaused() void QFutureInterfaceBase::toggleSuspended()
{ {
QMutexLocker locker(&d->m_mutex); QMutexLocker locker(&d->m_mutex);
if (d->state.loadRelaxed() & Paused) { if (d->state.loadRelaxed() & suspendingOrSuspended) {
switch_off(d->state, Paused | Suspended); switch_off(d->state, suspendingOrSuspended);
d->pausedWaitCondition.wakeAll(); d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed));
} else { } else {
switch_on(d->state, Paused); switch_on(d->state, Suspending);
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspending));
} }
} }
@ -150,10 +154,10 @@ void QFutureInterfaceBase::reportSuspended() const
QMutexLocker locker(&d->m_mutex); QMutexLocker locker(&d->m_mutex);
const int state = d->state; const int state = d->state;
if (!(state & Paused) || (state & Suspended)) if (!(state & Suspending) || (state & Suspended))
return; return;
switch_on(d->state, Suspended); switch_from_to(d->state, Suspending, Suspended);
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspended)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspended));
} }
@ -164,7 +168,7 @@ void QFutureInterfaceBase::setThrottled(bool enable)
switch_on(d->state, Throttled); switch_on(d->state, Throttled);
} else { } else {
switch_off(d->state, Throttled); switch_off(d->state, Throttled);
if (!(d->state.loadRelaxed() & Paused)) if (!(d->state.loadRelaxed() & suspendingOrSuspended))
d->pausedWaitCondition.wakeAll(); d->pausedWaitCondition.wakeAll();
} }
} }
@ -190,10 +194,17 @@ bool QFutureInterfaceBase::isFinished() const
return queryState(Finished); return queryState(Finished);
} }
bool QFutureInterfaceBase::isSuspending() const
{
return queryState(Suspending);
}
#if QT_DEPRECATED_SINCE(6, 0)
bool QFutureInterfaceBase::isPaused() const bool QFutureInterfaceBase::isPaused() const
{ {
return queryState(Paused); return queryState(static_cast<State>(suspendingOrSuspended));
} }
#endif
bool QFutureInterfaceBase::isSuspended() const bool QFutureInterfaceBase::isSuspended() const
{ {
@ -233,13 +244,13 @@ void QFutureInterfaceBase::waitForResume()
// return early if possible to avoid taking the mutex lock. // return early if possible to avoid taking the mutex lock.
{ {
const int state = d->state.loadRelaxed(); const int state = d->state.loadRelaxed();
if (!(state & Paused) || (state & Canceled)) if (!(state & suspendingOrSuspended) || (state & Canceled))
return; return;
} }
QMutexLocker lock(&d->m_mutex); QMutexLocker lock(&d->m_mutex);
const int state = d->state.loadRelaxed(); const int state = d->state.loadRelaxed();
if (!(state & Paused) || (state & Canceled)) if (!(state & suspendingOrSuspended) || (state & Canceled))
return; return;
// decrease active thread count since this thread will wait. // decrease active thread count since this thread will wait.
@ -576,7 +587,7 @@ void QFutureInterfaceBasePrivate::internal_setThrottled(bool enable)
switch_on(state, QFutureInterfaceBase::Throttled); switch_on(state, QFutureInterfaceBase::Throttled);
} else { } else {
switch_off(state, QFutureInterfaceBase::Throttled); switch_off(state, QFutureInterfaceBase::Throttled);
if (!(state.loadRelaxed() & QFutureInterfaceBase::Paused)) if (!(state.loadRelaxed() & suspendingOrSuspended))
pausedWaitCondition.wakeAll(); pausedWaitCondition.wakeAll();
} }
} }
@ -611,7 +622,8 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface
{ {
QMutexLocker locker(&m_mutex); 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::Started));
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
m_progressMinimum, m_progressMinimum,
@ -631,15 +643,15 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface
it.batchedAdvance(); it.batchedAdvance();
} }
if (state.loadRelaxed() & QFutureInterfaceBase::Suspended) if (currentState & QFutureInterfaceBase::Suspended)
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspended)); interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspended));
else if (state.loadRelaxed() & QFutureInterfaceBase::Paused) else if (currentState & QFutureInterfaceBase::Suspending)
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspending));
if (state.loadRelaxed() & QFutureInterfaceBase::Canceled) if (currentState & QFutureInterfaceBase::Canceled)
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
if (state.loadRelaxed() & QFutureInterfaceBase::Finished) if (currentState & QFutureInterfaceBase::Finished)
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished));
outputConnections.append(interface); outputConnections.append(interface);

View File

@ -82,11 +82,11 @@ public:
Started = 0x02, Started = 0x02,
Finished = 0x04, Finished = 0x04,
Canceled = 0x08, Canceled = 0x08,
Paused = 0x10, Suspending = 0x10,
Throttled = 0x20, Suspended = 0x20,
Throttled = 0x40,
// Pending means that the future depends on another one, which is not finished yet // Pending means that the future depends on another one, which is not finished yet
Pending = 0x40, Pending = 0x80,
Suspended = 0x80
}; };
QFutureInterfaceBase(State initialState = NoState); QFutureInterfaceBase(State initialState = NoState);
@ -125,15 +125,25 @@ public:
bool isStarted() const; bool isStarted() const;
bool isCanceled() const; bool isCanceled() const;
bool isFinished() const; bool isFinished() const;
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.")
bool isPaused() const; 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 isSuspended() const;
bool isThrottled() const; bool isThrottled() const;
bool isResultReadyAt(int index) const; bool isResultReadyAt(int index) const;
bool isValid() const; bool isValid() const;
void cancel(); void cancel();
void setPaused(bool paused); void setSuspended(bool suspend);
void togglePaused(); void toggleSuspended();
void reportSuspended() const; void reportSuspended() const;
void setThrottled(bool enable); void setThrottled(bool enable);

View File

@ -70,12 +70,12 @@ public:
Started, Started,
Finished, Finished,
Canceled, Canceled,
Paused, Suspending,
Suspended,
Resumed, Resumed,
Progress, Progress,
ProgressRange, ProgressRange,
ResultsReady, ResultsReady
Suspended
}; };
QFutureCallOutEvent() QFutureCallOutEvent()

View File

@ -64,12 +64,12 @@ QT_BEGIN_NAMESPACE
For convenience, several of QFuture's functions are also available in For convenience, several of QFuture's functions are also available in
QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(), QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(),
progressText(), isStarted(), isFinished(), isRunning(), isCanceled(), progressText(), isStarted(), isFinished(), isRunning(), isCanceled(),
isPaused(), waitForFinished(), result(), and resultAt(). The cancel(), isSuspending(), isSuspended(), waitForFinished(), result(), and resultAt().
setPaused(), pause(), resume(), and togglePaused() functions are slots in The cancel(), setSuspended(), suspend(), resume(), and toggleSuspended() functions
QFutureWatcher. are slots in QFutureWatcher.
Status changes are reported via the started(), finished(), canceled(), 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(), signals. Progress information is provided from the progressRangeChanged(),
void progressValueChanged(), and progressTextChanged() signals. void progressValueChanged(), and progressTextChanged() signals.
@ -85,7 +85,7 @@ QT_BEGIN_NAMESPACE
\snippet code/src_corelib_thread_qfuturewatcher.cpp 0 \snippet code/src_corelib_thread_qfuturewatcher.cpp 0
Be aware that not all running asynchronous computations can be canceled or 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. canceled; but the future returned by QtConcurrent::mappedReduced() can.
QFutureWatcher<void> is specialized to not contain any of the result QFutureWatcher<void> is specialized to not contain any of the result
@ -133,8 +133,12 @@ void QFutureWatcherBase::cancel()
futureInterface().cancel(); futureInterface().cancel();
} }
#if QT_DEPRECATED_SINCE(6, 0)
/*! \fn template <typename T> void QFutureWatcher<T>::setPaused(bool paused) /*! \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 If \a paused is true, this function pauses the asynchronous computation
represented by the future(). If the computation is already paused, this represented by the future(). If the computation is already paused, this
function does nothing. QFutureWatcher will not immediately stop delivering function does nothing. QFutureWatcher will not immediately stop delivering
@ -154,11 +158,14 @@ void QFutureWatcherBase::cancel()
*/ */
void QFutureWatcherBase::setPaused(bool paused) void QFutureWatcherBase::setPaused(bool paused)
{ {
futureInterface().setPaused(paused); futureInterface().setSuspended(paused);
} }
/*! \fn template <typename T> void QFutureWatcher<T>::pause() /*! \fn template <typename T> void QFutureWatcher<T>::pause()
\obsolete
Use suspend() instead.
Pauses the asynchronous computation represented by the future(). This is a Pauses the asynchronous computation represented by the future(). This is a
convenience method that simply calls setPaused(true). convenience method that simply calls setPaused(true).
@ -166,33 +173,96 @@ void QFutureWatcherBase::setPaused(bool paused)
*/ */
void QFutureWatcherBase::pause() 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() /*! \fn template <typename T> void QFutureWatcher<T>::resume()
Resumes the asynchronous computation represented by the future(). This is 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() void QFutureWatcherBase::resume()
{ {
futureInterface().setPaused(false); futureInterface().setSuspended(false);
} }
#if QT_DEPRECATED_SINCE(6, 0)
/*! \fn template <typename T> void QFutureWatcher<T>::togglePaused() /*! \fn template <typename T> void QFutureWatcher<T>::togglePaused()
\obsolete
Use toggleSuspended() instead.
Toggles the paused state of the asynchronous computation. In other words, 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 currently paused, calling this function resumes it;
if the computation is running, it becomes paused. This is a convenience if the computation is running, it is paused. This is a convenience method
method for calling setPaused(!isPaused()). for calling setPaused(!isPaused()).
\sa setPaused(), pause(), resume() \sa setPaused(), pause(), resume()
*/ */
void QFutureWatcherBase::togglePaused() 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 /*! \fn template <typename T> int QFutureWatcher<T>::progressValue() const
@ -286,8 +356,13 @@ bool QFutureWatcherBase::isCanceled() const
return futureInterface().queryState(QFutureInterfaceBase::Canceled); return futureInterface().queryState(QFutureInterfaceBase::Canceled);
} }
#if QT_DEPRECATED_SINCE(6, 0)
/*! \fn template <typename T> bool QFutureWatcher<T>::isPaused() const /*! \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 Returns \c true if the asynchronous computation has been paused with the
pause() function; otherwise returns \c false. pause() function; otherwise returns \c false.
@ -297,17 +372,42 @@ bool QFutureWatcherBase::isCanceled() const
\sa setPaused(), togglePaused(), isSuspended() \sa setPaused(), togglePaused(), isSuspended()
*/ */
bool QFutureWatcherBase::isPaused() const 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 /*! \fn template <typename T> bool QFutureWatcher<T>::isSuspended() const
Returns \c true if a paused asynchronous computation has been suspended, \since 6.0
and no more results or progress changes are expected.
\sa suspended(), paused(), isPaused() 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(), setSuspended(), isSuspending()
*/ */
bool QFutureWatcherBase::isSuspended() const bool QFutureWatcherBase::isSuspended() const
{ {
@ -439,10 +539,16 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
pendingResultsReady.storeRelaxed(0); pendingResultsReady.storeRelaxed(0);
emit q->canceled(); emit q->canceled();
break; break;
case QFutureCallOutEvent::Paused: case QFutureCallOutEvent::Suspending:
if (q->futureInterface().isCanceled()) if (q->futureInterface().isCanceled())
break; break;
emit q->suspending();
#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
emit q->paused(); emit q->paused();
QT_WARNING_POP
#endif
break; break;
case QFutureCallOutEvent::Suspended: case QFutureCallOutEvent::Suspended:
if (q->futureInterface().isCanceled()) if (q->futureInterface().isCanceled())
@ -540,7 +646,28 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
This signal is emitted if the watched future is canceled. 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() /*! \fn template <typename T> void QFutureWatcher<T>::paused()
\obsolete
Use suspending() instead.
This signal is emitted when the state of the watched future is This signal is emitted when the state of the watched future is
set to paused. set to paused.
@ -552,13 +679,17 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
\sa setPaused(), pause(), suspended() \sa setPaused(), pause(), suspended()
*/ */
#endif // QT_DEPRECATED_SINCE(6, 0)
/*! \fn template <typename T> void QFutureWatcher<T>::suspended() /*! \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 no more running computations. After receiving this signal no more result
ready or progress reporting signals are expected. ready or progress reporting signals are expected.
\sa setPaused(), pause(), paused() \sa setSuspended(), suspend(), suspended()
*/ */
/*! \fn template <typename T> void QFutureWatcher<T>::resumed() /*! \fn template <typename T> void QFutureWatcher<T>::resumed()

View File

@ -69,7 +69,11 @@ public:
bool isFinished() const; bool isFinished() const;
bool isRunning() const; bool isRunning() const;
bool isCanceled() const; bool isCanceled() const;
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_X_6_0("Use isSuspending() or isSuspended() instead.")
bool isPaused() const; bool isPaused() const;
#endif
bool isSuspending() const;
bool isSuspended() const; bool isSuspended() const;
void waitForFinished(); void waitForFinished();
@ -82,7 +86,11 @@ Q_SIGNALS:
void started(); void started();
void finished(); void finished();
void canceled(); void canceled();
#if QT_DEPRECATED_SINCE(6, 0)
QT_DEPRECATED_VERSION_X_6_0("Use suspending() instead.")
void paused(); void paused();
#endif
void suspending();
void suspended(); void suspended();
void resumed(); void resumed();
void resultReadyAt(int resultIndex); void resultReadyAt(int resultIndex);
@ -93,10 +101,21 @@ Q_SIGNALS:
public Q_SLOTS: public Q_SLOTS:
void cancel(); void cancel();
void setPaused(bool paused); void setSuspended(bool suspend);
void pause(); void suspend();
void resume(); 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();
QT_DEPRECATED_VERSION_X_6_0("Use toggleSuspended() instead.")
void togglePaused(); void togglePaused();
#endif
protected: protected:
void connectNotify (const QMetaMethod &signal) override; void connectNotify (const QMetaMethod &signal) override;
@ -148,8 +167,11 @@ public:
bool isFinished() const; bool isFinished() const;
bool isRunning() const; bool isRunning() const;
bool isCanceled() const; bool isCanceled() const;
#if QT_DEPRECATED_SINCE(6, 0)
bool isPaused() const; bool isPaused() const;
bool isSuspended() const #endif
bool isSuspending() const;
bool isSuspended() const;
void waitForFinished(); void waitForFinished();
@ -159,7 +181,10 @@ Q_SIGNALS:
void started(); void started();
void finished(); void finished();
void canceled(); void canceled();
#if QT_DEPRECATED_SINCE(6, 0)
void paused(); void paused();
#endif
void suspending();
void suspended(); void suspended();
void resumed(); void resumed();
void resultReadyAt(int resultIndex); void resultReadyAt(int resultIndex);
@ -170,11 +195,17 @@ Q_SIGNALS:
public Q_SLOTS: public Q_SLOTS:
void cancel(); void cancel();
void setSuspended(bool suspend);
void suspend();
void resume();
void toggleSuspended();
#if QT_DEPRECATED_SINCE(6, 0)
void setPaused(bool paused); void setPaused(bool paused);
void pause(); void pause();
void resume();
void togglePaused(); void togglePaused();
#endif #endif // QT_DEPRECATED_SINCE(6, 0)
#endif // Q_QDOC
private: private:
QFuture<T> m_future; QFuture<T> m_future;

View File

@ -112,7 +112,10 @@ private slots:
void implicitConversions(); void implicitConversions();
void iterators(); void iterators();
void iteratorsThread(); void iteratorsThread();
#if QT_DEPRECATED_SINCE(6, 0)
void pause(); void pause();
void suspendCheckPaused();
#endif
void suspend(); void suspend();
void throttling(); void throttling();
void voidConversions(); void voidConversions();
@ -1315,6 +1318,9 @@ public:
QSet<int> reportedProgress; QSet<int> reportedProgress;
}; };
#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
void tst_QFuture::pause() void tst_QFuture::pause()
{ {
QFutureInterface<void> Interface; QFutureInterface<void> Interface;
@ -1335,39 +1341,98 @@ void tst_QFuture::pause()
Interface.reportFinished(); 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() void tst_QFuture::suspend()
{ {
QFutureInterface<void> interface; QFutureInterface<void> interface;
interface.reportStarted(); interface.reportStarted();
QFuture<void> f = interface.future(); QFuture<void> f = interface.future();
QVERIFY(!interface.isSuspended()); QVERIFY(!f.isSuspended());
interface.reportSuspended(); interface.reportSuspended();
QVERIFY(!interface.isSuspended()); QVERIFY(!f.isSuspended());
QVERIFY(!f.isSuspending());
// pause f.suspend();
interface.togglePaused(); QVERIFY(f.isSuspending());
QVERIFY(!interface.isSuspended()); QVERIFY(!f.isSuspended());
QVERIFY(interface.isPaused());
// resume when still suspending
f.resume();
QVERIFY(!f.isSuspending());
QVERIFY(!f.isSuspended());
// suspend again
f.suspend();
QVERIFY(f.isSuspending());
QVERIFY(!f.isSuspended());
interface.reportSuspended(); interface.reportSuspended();
QVERIFY(interface.isSuspended()); QVERIFY(!f.isSuspending());
QVERIFY(interface.isPaused()); QVERIFY(f.isSuspended());
// resume // resume after suspended
interface.togglePaused(); f.resume();
QVERIFY(!interface.isSuspended()); QVERIFY(!f.isSuspending());
QVERIFY(!interface.isPaused()); QVERIFY(!f.isSuspended());
// pause again // suspend again and cancel
interface.togglePaused(); f.suspend();
interface.reportSuspended(); interface.reportSuspended();
interface.reportCanceled(); interface.reportCanceled();
QVERIFY(!interface.isSuspended()); QVERIFY(!f.isSuspending());
QVERIFY(!interface.isPaused()); QVERIFY(!f.isSuspended());
QVERIFY(interface.isCanceled()); QVERIFY(f.isCanceled());
interface.reportFinished(); interface.reportFinished();
} }
@ -2715,7 +2780,14 @@ void tst_QFuture::testFutureTaken(QFuture<T> &noMoreFuture)
QCOMPARE(noMoreFuture.resultCount(), 0); QCOMPARE(noMoreFuture.resultCount(), 0);
QCOMPARE(noMoreFuture.isStarted(), false); QCOMPARE(noMoreFuture.isStarted(), false);
QCOMPARE(noMoreFuture.isRunning(), 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); QCOMPARE(noMoreFuture.isPaused(), false);
QT_WARNING_POP
#endif
QCOMPARE(noMoreFuture.isFinished(), false); QCOMPARE(noMoreFuture.isFinished(), false);
QCOMPARE(noMoreFuture.progressValue(), 0); QCOMPARE(noMoreFuture.progressValue(), 0);
} }

View File

@ -57,9 +57,13 @@ private slots:
void sharedFutureInterface(); void sharedFutureInterface();
void changeFuture(); void changeFuture();
void cancelEvents(); void cancelEvents();
#if QT_DEPRECATED_SINCE(6, 0)
void pauseEvents(); void pauseEvents();
void pausedSuspendedOrder();
#endif
void suspendEvents();
void suspended(); void suspended();
void suspendedEvents(); void suspendedEventsOrder();
void finishedState(); void finishedState();
void throttling(); void throttling();
void incrementalMapResults(); void incrementalMapResults();
@ -548,12 +552,21 @@ void callInterface(T &obj)
obj.isFinished(); obj.isFinished();
obj.isRunning(); obj.isRunning();
obj.isCanceled(); obj.isCanceled();
obj.isPaused(); obj.isSuspended();
obj.isSuspending();
obj.cancel(); obj.cancel();
obj.pause(); obj.suspend();
obj.resume(); obj.resume();
obj.toggleSuspended();
#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
obj.isPaused();
obj.pause();
obj.togglePaused(); obj.togglePaused();
QT_WARNING_POP
#endif
obj.waitForFinished(); obj.waitForFinished();
const T& objConst = obj; const T& objConst = obj;
@ -566,7 +579,14 @@ void callInterface(T &obj)
objConst.isFinished(); objConst.isFinished();
objConst.isRunning(); objConst.isRunning();
objConst.isCanceled(); objConst.isCanceled();
objConst.isSuspending();
objConst.isSuspended();
#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
objConst.isPaused(); objConst.isPaused();
QT_WARNING_POP
#endif
} }
template <typename T> template <typename T>
@ -665,6 +685,9 @@ void tst_QFutureWatcher::cancelEvents()
QCOMPARE(resultReadySpy.count(), 0); 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 // Tests that events from paused futures are saved and
// delivered on resume. // delivered on resume.
void tst_QFutureWatcher::pauseEvents() 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() void tst_QFutureWatcher::suspended()
{ {
QFutureWatcher<void> watcher; QFutureWatcher<void> watcher;
QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt); 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); QSignalSpy pausedSpy(&watcher, &QFutureWatcher<int>::paused);
QT_WARNING_POP
#endif
QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<int>::suspending);
QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<int>::suspended); QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<int>::suspended);
QSignalSpy finishedSpy(&watcher, &QFutureWatcher<int>::finished); QSignalSpy finishedSpy(&watcher, &QFutureWatcher<int>::finished);
@ -748,13 +880,16 @@ void tst_QFutureWatcher::suspended()
}); });
watcher.setFuture(future); watcher.setFuture(future);
// Allow some threads to start before pausing. // Allow some threads to start before suspending.
QThread::msleep(200); QThread::msleep(200);
watcher.pause(); watcher.suspend();
watcher.pause(); watcher.suspend();
QTRY_COMPARE(suspendedSpy.count(), 1); // suspended() should be emitted only once 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 QCOMPARE(pausedSpy.count(), 2); // paused() is emitted as many times as requested
#endif
// Make sure QFutureWatcher::resultReadyAt() is emitted only for already started threads. // Make sure QFutureWatcher::resultReadyAt() is emitted only for already started threads.
const auto resultReadyAfterPaused = resultReadySpy.count(); const auto resultReadyAfterPaused = resultReadySpy.count();
@ -775,41 +910,41 @@ void tst_QFutureWatcher::suspended()
QCOMPARE(resultReadySpy.count(), numValues - resultReadyAfterPaused); QCOMPARE(resultReadySpy.count(), numValues - resultReadyAfterPaused);
} }
void tst_QFutureWatcher::suspendedEvents() void tst_QFutureWatcher::suspendedEventsOrder()
{ {
QFutureInterface<void> iface; QFutureInterface<void> iface;
iface.reportStarted(); iface.reportStarted();
QFutureWatcher<void> watcher; QFutureWatcher<void> watcher;
QSignalSpy pausedSpy(&watcher, &QFutureWatcher<void>::paused); QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<void>::suspending);
QVERIFY(pausedSpy.isValid()); QVERIFY(suspendingSpy.isValid());
QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<void>::suspended); QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<void>::suspended);
QVERIFY(suspendedSpy.isValid()); QVERIFY(suspendedSpy.isValid());
bool pausedBeforeSuspended = false; bool suspendingBeforeSuspended = false;
bool notSuspendedBeforePasused = false; bool notSuspendedBeforeSuspending = false;
connect(&watcher, &QFutureWatcher<void>::paused, connect(&watcher, &QFutureWatcher<void>::suspending,
[&] { notSuspendedBeforePasused = (suspendedSpy.count() == 0); }); [&] { notSuspendedBeforeSuspending = (suspendedSpy.count() == 0); });
connect(&watcher, &QFutureWatcher<void>::suspended, connect(&watcher, &QFutureWatcher<void>::suspended,
[&] { pausedBeforeSuspended = (pausedSpy.count() == 1); }); [&] { suspendingBeforeSuspended = (suspendingSpy.count() == 1); });
watcher.setFuture(iface.future()); watcher.setFuture(iface.future());
iface.reportSuspended(); iface.reportSuspended();
// Make sure reportPaused() is ignored if the state is not paused // Make sure reportPaused() is ignored if the state is not paused
pausedSpy.wait(100); suspendingSpy.wait(100);
QCOMPARE(pausedSpy.count(), 0); QCOMPARE(suspendingSpy.count(), 0);
QCOMPARE(suspendedSpy.count(), 0); QCOMPARE(suspendedSpy.count(), 0);
iface.setPaused(true); iface.setSuspended(true);
iface.reportSuspended(); iface.reportSuspended();
QTRY_COMPARE(suspendedSpy.count(), 1); QTRY_COMPARE(suspendedSpy.count(), 1);
QCOMPARE(pausedSpy.count(), 1); QCOMPARE(suspendingSpy.count(), 1);
QVERIFY(notSuspendedBeforePasused); QVERIFY(notSuspendedBeforeSuspending);
QVERIFY(pausedBeforeSuspended); QVERIFY(suspendingBeforeSuspended);
iface.reportFinished(); iface.reportFinished();
} }