summaryrefslogtreecommitdiffstats
path: root/tests
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 /tests
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 'tests')
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp38
-rw-r--r--tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp91
2 files changed, 129 insertions, 0 deletions
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index a7f308de59..d647ce6eba 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -113,6 +113,7 @@ private slots:
void iterators();
void iteratorsThread();
void pause();
+ void suspend();
void throttling();
void voidConversions();
#ifndef QT_NO_EXCEPTIONS
@@ -1334,6 +1335,43 @@ void tst_QFuture::pause()
Interface.reportFinished();
}
+void tst_QFuture::suspend()
+{
+ QFutureInterface<void> interface;
+
+ interface.reportStarted();
+ QFuture<void> f = interface.future();
+ QVERIFY(!interface.isSuspended());
+
+ interface.reportSuspended();
+ QVERIFY(!interface.isSuspended());
+
+ // pause
+ interface.togglePaused();
+ QVERIFY(!interface.isSuspended());
+ QVERIFY(interface.isPaused());
+
+ interface.reportSuspended();
+ QVERIFY(interface.isSuspended());
+ QVERIFY(interface.isPaused());
+
+ // resume
+ interface.togglePaused();
+ QVERIFY(!interface.isSuspended());
+ QVERIFY(!interface.isPaused());
+
+ // pause again
+ interface.togglePaused();
+ interface.reportSuspended();
+
+ interface.reportCanceled();
+ QVERIFY(!interface.isSuspended());
+ QVERIFY(!interface.isPaused());
+ QVERIFY(interface.isCanceled());
+
+ interface.reportFinished();
+}
+
class ResultObject : public QObject
{
Q_OBJECT
diff --git a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
index 8b332e67fe..13fb587607 100644
--- a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
+++ b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
@@ -58,6 +58,8 @@ private slots:
void changeFuture();
void cancelEvents();
void pauseEvents();
+ void suspended();
+ void suspendedEvents();
void finishedState();
void throttling();
void incrementalMapResults();
@@ -723,6 +725,95 @@ void tst_QFutureWatcher::pauseEvents()
}
}
+void tst_QFutureWatcher::suspended()
+{
+ QFutureWatcher<void> watcher;
+ QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt);
+ QSignalSpy pausedSpy(&watcher, &QFutureWatcher<int>::paused);
+ QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<int>::suspended);
+ QSignalSpy finishedSpy(&watcher, &QFutureWatcher<int>::finished);
+
+ const int numValues = 25;
+ std::vector<int> values(numValues, 0);
+ std::atomic_int count = 0;
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(3);
+
+ QFuture<int> future = QtConcurrent::mapped(&pool, values, [&](int value) {
+ ++count;
+ // Sleep, to make sure not all threads will start at once.
+ QThread::msleep(50);
+ return value;
+ });
+ watcher.setFuture(future);
+
+ // Allow some threads to start before pausing.
+ QThread::msleep(200);
+
+ watcher.pause();
+ watcher.pause();
+ QTRY_COMPARE(suspendedSpy.count(), 1); // suspended() should be emitted only once
+ QCOMPARE(pausedSpy.count(), 2); // paused() is emitted as many times as requested
+
+ // Make sure QFutureWatcher::resultReadyAt() is emitted only for already started threads.
+ const auto resultReadyAfterPaused = resultReadySpy.count();
+ QCOMPARE(resultReadyAfterPaused, count);
+
+ // Make sure no more results are reported before resuming.
+ QThread::msleep(200);
+ QCOMPARE(resultReadyAfterPaused, resultReadySpy.count());
+ resultReadySpy.clear();
+
+ watcher.resume();
+ QTRY_COMPARE(finishedSpy.count(), 1);
+
+ // Make sure that no more suspended() signals have been emitted.
+ QCOMPARE(suspendedSpy.count(), 1);
+
+ // Make sure the rest of results were reported after resume.
+ QCOMPARE(resultReadySpy.count(), numValues - resultReadyAfterPaused);
+}
+
+void tst_QFutureWatcher::suspendedEvents()
+{
+ 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 notSuspendedBeforePasused = false;
+ connect(&watcher, &QFutureWatcher<void>::paused,
+ [&] { notSuspendedBeforePasused = (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(notSuspendedBeforePasused);
+ QVERIFY(pausedBeforeSuspended);
+
+ iface.reportFinished();
+}
+
// Test that the finished state for the watcher gets
// set when the finished event is delivered.
// This means it will lag the finished state for the future,