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();
}
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();
}
}

View File

@ -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();

View File

@ -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(); }

View File

@ -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,32 +243,22 @@
\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()
\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>::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()
\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
@ -268,6 +266,82 @@
\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

View File

@ -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);

View File

@ -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);

View File

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

View File

@ -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
\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
{
@ -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()

View File

@ -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 setPaused(bool paused);
void pause();
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();
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;

View File

@ -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());
// pause
interface.togglePaused();
QVERIFY(!interface.isSuspended());
QVERIFY(interface.isPaused());
f.suspend();
QVERIFY(f.isSuspending());
QVERIFY(!f.isSuspended());
// resume when still suspending
f.resume();
QVERIFY(!f.isSuspending());
QVERIFY(!f.isSuspended());
// 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);
}

View File

@ -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();
}