summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2020-05-20 11:39:39 +0200
committerSona Kurazyan <sona.kurazyan@qt.io>2020-05-29 16:58:43 +0200
commit2f15927f01ceef0aca490746302a5ea57ea9441c (patch)
treec4978b801a1e7db5b63fd091182fff2394a36b7f /src
parent9b0e23ef8a915a8c58808fa356f771ecdb6f020c (diff)
Add a way of notifying QFutureWatcher when pause is in effect
Because setting QFutureInterface to paused state does not mean that the computations that are already in progress will stop immediately, it may be useful to get notified when pause actually takes effect. Introduced the QFutureWatcher::suspended() signal, to be emitted when there are no more computations in progress, and no more result ready or progress reporting signals will be emitted, i.e. when pause took effect. Added {QFuture, QFutureWatcher}::isSuspended() methods for checking if pause took effect. QtConcurrent will now to send QFutureCallOutEvent::Suspended event when the state is paused and there are no more active threads. [ChangeLog][QtCore][QFutureWatcher] Added a new QFutureWatcher::suspended() signal, to be emitted when pause took effect, meaning that there are no more computations in progress. Added {QFuture, QFutureWatcher}::isSuspended() methods for checking if pause took effect. Fixes: QTBUG-12152 Change-Id: I88f2ad24d800cd6293dec63977d45bd35f9a09f0 Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/concurrent/qtconcurrentthreadengine.cpp15
-rw-r--r--src/concurrent/qtconcurrentthreadengine.h1
-rw-r--r--src/corelib/thread/qfuture.h1
-rw-r--r--src/corelib/thread/qfuture.qdoc17
-rw-r--r--src/corelib/thread/qfutureinterface.cpp29
-rw-r--r--src/corelib/thread/qfutureinterface.h5
-rw-r--r--src/corelib/thread/qfutureinterface_p.h3
-rw-r--r--src/corelib/thread/qfuturewatcher.cpp39
-rw-r--r--src/corelib/thread/qfuturewatcher.h4
9 files changed, 97 insertions, 17 deletions
diff --git a/src/concurrent/qtconcurrentthreadengine.cpp b/src/concurrent/qtconcurrentthreadengine.cpp
index 7dfc29c68f..7ea606f60b 100644
--- a/src/concurrent/qtconcurrentthreadengine.cpp
+++ b/src/concurrent/qtconcurrentthreadengine.cpp
@@ -219,6 +219,12 @@ void ThreadEngineBase::acquireBarrierSemaphore()
barrier.acquire();
}
+void ThreadEngineBase::reportIfPausedDone() const
+{
+ if (futureInterface && futureInterface->isPaused())
+ futureInterface->reportSuspended();
+}
+
bool ThreadEngineBase::isCanceled()
{
if (futureInterface)
@@ -304,8 +310,15 @@ void ThreadEngineBase::run() // implements QRunnable.
// struct wants to be throttled by making a worker thread exit.
// Respect that request unless this is the only worker thread left
// running, in which case it has to keep going.
- if (threadThrottleExit())
+ 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
+ // in effect (because all previous threads have already exited).
+ // Report the "Suspended" state.
+ reportIfPausedDone();
+ }
}
#ifndef QT_NO_EXCEPTIONS
diff --git a/src/concurrent/qtconcurrentthreadengine.h b/src/concurrent/qtconcurrentthreadengine.h
index eb11c34c06..4e7e8d0b81 100644
--- a/src/concurrent/qtconcurrentthreadengine.h
+++ b/src/concurrent/qtconcurrentthreadengine.h
@@ -99,6 +99,7 @@ public:
void setProgressValue(int progress);
void setProgressRange(int minimum, int maximum);
void acquireBarrierSemaphore();
+ void reportIfPausedDone() const;
protected: // The user overrides these:
virtual void start() {}
diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h
index 22ab0c13de..4f9ba0bd6b 100644
--- a/src/corelib/thread/qfuture.h
+++ b/src/corelib/thread/qfuture.h
@@ -111,6 +111,7 @@ public:
void setPaused(bool paused) { d.setPaused(paused); }
bool isPaused() const { return d.isPaused(); }
+ bool isSuspended() const { return d.isSuspended(); }
void pause() { setPaused(true); }
void resume() { setPaused(false); }
void togglePaused() { d.togglePaused(); }
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 1846aa377d..dd55c3377b 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -116,8 +116,8 @@
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(), or isPaused()
- functions.
+ the isCanceled(), isStarted(), isFinished(), isRunning(), isPaused()
+ or isSuspended() functions.
QFuture is a lightweight reference counted class that can be passed by
value.
@@ -229,9 +229,18 @@
pause() function; otherwise returns \c false.
Be aware that the computation may still be running even though this
- function returns \c true. See setPaused() for more details.
+ function returns \c true. See setPaused() for more details. To check
+ if pause actually took effect, use isSuspended() instead.
- \sa setPaused(), togglePaused()
+ \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()
diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp
index 92b2df7c15..1d8e4ac1a4 100644
--- a/src/corelib/thread/qfutureinterface.cpp
+++ b/src/corelib/thread/qfutureinterface.cpp
@@ -110,7 +110,7 @@ void QFutureInterfaceBase::cancel()
if (d->state.loadRelaxed() & Canceled)
return;
- switch_from_to(d->state, Paused, Canceled);
+ switch_from_to(d->state, Paused | Suspended, Canceled);
d->waitCondition.wakeAll();
d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
@@ -124,7 +124,7 @@ void QFutureInterfaceBase::setPaused(bool paused)
switch_on(d->state, Paused);
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused));
} else {
- switch_off(d->state, Paused);
+ switch_off(d->state, Paused | Suspended);
d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed));
}
@@ -134,7 +134,7 @@ void QFutureInterfaceBase::togglePaused()
{
QMutexLocker locker(&d->m_mutex);
if (d->state.loadRelaxed() & Paused) {
- switch_off(d->state, Paused);
+ switch_off(d->state, Paused | Suspended);
d->pausedWaitCondition.wakeAll();
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed));
} else {
@@ -143,6 +143,20 @@ void QFutureInterfaceBase::togglePaused()
}
}
+void QFutureInterfaceBase::reportSuspended() const
+{
+ // Needs to be called when pause is in effect,
+ // i.e. no more events will be reported.
+
+ QMutexLocker locker(&d->m_mutex);
+ const int state = d->state;
+ if (!(state & Paused) || (state & Suspended))
+ return;
+
+ switch_on(d->state, Suspended);
+ d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Suspended));
+}
+
void QFutureInterfaceBase::setThrottled(bool enable)
{
QMutexLocker lock(&d->m_mutex);
@@ -181,6 +195,11 @@ bool QFutureInterfaceBase::isPaused() const
return queryState(Paused);
}
+bool QFutureInterfaceBase::isSuspended() const
+{
+ return queryState(Suspended);
+}
+
bool QFutureInterfaceBase::isThrottled() const
{
return queryState(Throttled);
@@ -612,7 +631,9 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface
it.batchedAdvance();
}
- if (state.loadRelaxed() & QFutureInterfaceBase::Paused)
+ if (state.loadRelaxed() & QFutureInterfaceBase::Suspended)
+ interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspended));
+ else if (state.loadRelaxed() & QFutureInterfaceBase::Paused)
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Paused));
if (state.loadRelaxed() & QFutureInterfaceBase::Canceled)
diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h
index 2f9b455d8d..ce8985f866 100644
--- a/src/corelib/thread/qfutureinterface.h
+++ b/src/corelib/thread/qfutureinterface.h
@@ -85,7 +85,8 @@ public:
Paused = 0x10,
Throttled = 0x20,
// Pending means that the future depends on another one, which is not finished yet
- Pending = 0x40
+ Pending = 0x40,
+ Suspended = 0x80
};
QFutureInterfaceBase(State initialState = NoState);
@@ -125,6 +126,7 @@ public:
bool isCanceled() const;
bool isFinished() const;
bool isPaused() const;
+ bool isSuspended() const;
bool isThrottled() const;
bool isResultReadyAt(int index) const;
bool isValid() const;
@@ -132,6 +134,7 @@ public:
void cancel();
void setPaused(bool paused);
void togglePaused();
+ void reportSuspended() const;
void setThrottled(bool enable);
void waitForFinished();
diff --git a/src/corelib/thread/qfutureinterface_p.h b/src/corelib/thread/qfutureinterface_p.h
index 95ad09d535..86160e8532 100644
--- a/src/corelib/thread/qfutureinterface_p.h
+++ b/src/corelib/thread/qfutureinterface_p.h
@@ -74,7 +74,8 @@ public:
Resumed,
Progress,
ProgressRange,
- ResultsReady
+ ResultsReady,
+ Suspended
};
QFutureCallOutEvent()
diff --git a/src/corelib/thread/qfuturewatcher.cpp b/src/corelib/thread/qfuturewatcher.cpp
index 1ab3efee64..12469d4884 100644
--- a/src/corelib/thread/qfuturewatcher.cpp
+++ b/src/corelib/thread/qfuturewatcher.cpp
@@ -69,8 +69,8 @@ QT_BEGIN_NAMESPACE
QFutureWatcher.
Status changes are reported via the started(), finished(), canceled(),
- paused(), resumed(), resultReadyAt(), and resultsReadyAt() signals.
- Progress information is provided from the progressRangeChanged(),
+ paused(), resumed(), suspended(), resultReadyAt(), and resultsReadyAt()
+ signals. Progress information is provided from the progressRangeChanged(),
void progressValueChanged(), and progressTextChanged() signals.
Throttling control is provided by the setPendingResultsLimit() function.
@@ -292,15 +292,28 @@ bool QFutureWatcherBase::isCanceled() const
pause() function; otherwise returns \c false.
Be aware that the computation may still be running even though this
- function returns \c true. See setPaused() for more details.
+ function returns \c true. See setPaused() for more details. To check
+ if pause actually took effect, use isSuspended() instead.
- \sa setPaused(), togglePaused()
+ \sa setPaused(), togglePaused(), isSuspended()
*/
bool QFutureWatcherBase::isPaused() const
{
return futureInterface().queryState(QFutureInterfaceBase::Paused);
}
+/*! \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.
+
+ \sa suspended(), paused(), isPaused()
+*/
+bool QFutureWatcherBase::isSuspended() const
+{
+ return futureInterface().isSuspended();
+}
+
/*! \fn template <typename T> void QFutureWatcher<T>::waitForFinished()
Waits for the asynchronous computation to finish (including cancel()ed
@@ -431,6 +444,11 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
break;
emit q->paused();
break;
+ case QFutureCallOutEvent::Suspended:
+ if (q->futureInterface().isCanceled())
+ break;
+ emit q->suspended();
+ break;
case QFutureCallOutEvent::Resumed:
if (q->futureInterface().isCanceled())
break;
@@ -529,9 +547,18 @@ void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event)
\note This signal only informs that pause has been requested. It
doesn't indicate that all background operations are stopped. Signals
for computations that were in progress at the moment of pausing will
- still be delivered.
+ still be delivered. To to be informed when pause() actually
+ took effect, use the suspended() signal.
+
+ \sa setPaused(), pause(), suspended()
+*/
+
+/*! \fn template <typename T> void QFutureWatcher<T>::suspended()
+ This signal is emitted when pause() 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()
+ \sa setPaused(), pause(), paused()
*/
/*! \fn template <typename T> void QFutureWatcher<T>::resumed()
diff --git a/src/corelib/thread/qfuturewatcher.h b/src/corelib/thread/qfuturewatcher.h
index 214dc37f01..0c8c1ec247 100644
--- a/src/corelib/thread/qfuturewatcher.h
+++ b/src/corelib/thread/qfuturewatcher.h
@@ -70,6 +70,7 @@ public:
bool isRunning() const;
bool isCanceled() const;
bool isPaused() const;
+ bool isSuspended() const;
void waitForFinished();
@@ -82,6 +83,7 @@ Q_SIGNALS:
void finished();
void canceled();
void paused();
+ void suspended();
void resumed();
void resultReadyAt(int resultIndex);
void resultsReadyAt(int beginIndex, int endIndex);
@@ -147,6 +149,7 @@ public:
bool isRunning() const;
bool isCanceled() const;
bool isPaused() const;
+ bool isSuspended() const
void waitForFinished();
@@ -157,6 +160,7 @@ Q_SIGNALS:
void finished();
void canceled();
void paused();
+ void suspended();
void resumed();
void resultReadyAt(int resultIndex);
void resultsReadyAt(int beginIndex, int endIndex);