QThread::isFinished should return true from finished()
authorOlivier Goffart <ogoffart@kde.org>
Thu, 3 Nov 2011 13:11:34 +0000 (14:11 +0100)
committerQt by Nokia <qt-info@nokia.com>
Thu, 3 Nov 2011 17:43:52 +0000 (18:43 +0100)
and isRunning() should return false.

This restore the Qt 4.7 behaviour

In Qt 4.7, the finished() was called with the thread's intenal mutex
locked. Which mean that:
 - Call to isRunning or isFinished called from a slot connected to
   finish within the thread would deadlock. (Hence no compatibility
   to keep here)
 - Call to isRunning or isFinished from a slot connected with
   QueuedConnection in another thread would lock the mutex until
   the destructors are finished. and then return as if the thread have
   finished.

Change-Id: I963eccae8f7634aff90cc4bbab6ca886a78e35eb
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
src/corelib/thread/qthread.cpp
tests/auto/corelib/thread/qthread/tst_qthread.cpp

index 7a2e4b8..6cc8a48 100644 (file)
@@ -422,7 +422,7 @@ bool QThread::isFinished() const
 {
     Q_D(const QThread);
     QMutexLocker locker(&d->mutex);
-    return d->finished;
+    return d->finished || d->isInFinish;
 }
 
 /*!
@@ -434,7 +434,7 @@ bool QThread::isRunning() const
 {
     Q_D(const QThread);
     QMutexLocker locker(&d->mutex);
-    return d->running;
+    return d->running && !d->isInFinish;
 }
 
 /*!
index f832995..bf9faf1 100644 (file)
@@ -111,6 +111,7 @@ private slots:
     void destroyFinishRace();
     void startFinishRace();
     void startAndQuitCustomEventLoop();
+    void isRunningInFinished();
 
 #ifndef Q_OS_WINCE
     void stressTest();
@@ -1199,6 +1200,39 @@ void tst_QThread::startAndQuitCustomEventLoop()
    }
 }
 
+class FinishedTestObject : public QObject {
+    Q_OBJECT
+public:
+    FinishedTestObject() : ok(false) {}
+    bool ok;
+public slots:
+    void slotFinished() {
+        QThread *t = qobject_cast<QThread *>(sender());
+        ok = t && t->isFinished() && !t->isRunning();
+    }
+};
+
+void tst_QThread::isRunningInFinished()
+{
+    for (int i = 0; i < 15; i++) {
+        QThread thread;
+        thread.start();
+        FinishedTestObject localObject;
+        FinishedTestObject inThreadObject;
+        localObject.setObjectName("...");
+        inThreadObject.moveToThread(&thread);
+        connect(&thread, SIGNAL(finished()), &localObject, SLOT(slotFinished()));
+        connect(&thread, SIGNAL(finished()), &inThreadObject, SLOT(slotFinished()));
+        QEventLoop loop;
+        connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
+        QMetaObject::invokeMethod(&thread, "quit", Qt::QueuedConnection);
+        loop.exec();
+        QVERIFY(!thread.isRunning());
+        QVERIFY(thread.isFinished());
+        QVERIFY(localObject.ok);
+        QVERIFY(inThreadObject.ok);
+    }
+}
 
 QTEST_MAIN(tst_QThread)
 #include "tst_qthread.moc"