PDA

View Full Version : QThread::isRunning returns true after emitting finished signal



mentalmushroom
30th July 2012, 12:52
After updating Qt 4.7.2 to Qt 4.8.2 I've noticed something strange in QThread behavior. It seems like isRunning returns true even when the thread is finished (the finished signal is already emitted). The following code shows the issue: it prints "the thread is finished, isRunning = true" from the handleThreadFinished slot connected to the thread's finished signal. I've encountered a few new bugs in my application because of this change. Was this behavior intended?



#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>

using namespace std;

class MyThread: public QThread
{
protected:
virtual void run()
{
QTimer::singleShot(1000, this, SLOT(quit()));
exec();
//QThread::run();
}
};

class Test: public QObject
{
Q_OBJECT

public slots:
void run()
{
t = new MyThread;
connect(t, SIGNAL(finished()), this, SLOT(handleThreadFinished()));
t->start();
}

private slots:
void handleThreadFinished()
{
cout << "the thread is finished, isRunning = " << (t->isRunning() ? "true" : "false") << endl;
t->deleteLater();
}

private:
MyThread *t;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
QTimer::singleShot(0, &test, SLOT(run()));
return a.exec();
}

#include "main.moc"

high_flyer
30th July 2012, 15:50
Does this behavior persists if you call start() instead of run()?

mentalmushroom
30th July 2012, 15:54
I am already calling start() for the thread (see the line 28). or did you mean something else?

high_flyer
30th July 2012, 18:47
Then why do you call run() from your timer in main()?
Oh now I see... its a bad idea to call the methods with the same names specially when you want to test things like that.
You also are not terminating the thread but let the application end it.
This also is a bad idea to test the still running problem.
Name your methods with meaningful names.
Stop the thread, have the slot get called by the ending of the thread and test for isRunnning() after that.

mentalmushroom
30th July 2012, 18:57
I was trying many things and just forgot to change this to the ordinary call. run is a name of my own slot of the Test object (that is not a thread, therefore doesn't have a start method) created for signal/slot communication. However, it doesn't matter in this case how to call run - the issue occurs anyway.

amleto
30th July 2012, 19:10
interesting. does it also return true for isFinished?

mentalmushroom
30th July 2012, 19:12
interesting. does it also return true for isFinished?
yes, it does

amleto
30th July 2012, 19:13
well, plainly, that is silly. How can it be running AND finished? I would report it.

mentalmushroom
30th July 2012, 19:25
well, plainly, that is silly. How can it be running AND finished? I would report it.
Sorry, i was wrong. In the slot handling finished signal it returns false for isFinished, but isn't it strange also?


You also are not terminating the thread but let the application end it. This also is a bad idea to test the still running problem.
The thread is automatically terminated in 1 second. Why should I stop it?


Stop the thread, have the slot get called by the ending of the thread and test for isRunnning() after that.
Not sure what you meant. The QThread::finished documentation says "This signal is emitted when the thread has finished executing.". Doesn't it mean it should return false for isRunning and true for isFinished at that moment?

The updated code:



#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>

#include <QLocale>
#include <QStringList>
#include <QDebug>

using namespace std;

class MyThread: public QThread
{
protected:
virtual void run()
{
QTimer::singleShot(1000, this, SLOT(quit()));
exec();
//QThread::run();
}
};

class Test: public QObject
{
Q_OBJECT

public slots:
void start()
{
t = new MyThread;
connect(t, SIGNAL(finished()), this, SLOT(handleThreadFinished()), Qt::QueuedConnection);
t->start();
}

private slots:
void handleThreadFinished()
{
cout << "the thread is finished, isRunning = " << (t->isRunning() ? "true" : "false") << " isFinished = " << (t->isFinished() ? "true" : "false") << endl;
t->deleteLater();
}

private:
MyThread *t;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
test.start();
return a.exec();
}

#include "main.moc"

amleto
30th July 2012, 19:27
The thread is automatically terminated in 1 second. Why should I stop it?


perhaps he means that you 'new' it, but it is never 'delete'd

mentalmushroom
1st August 2012, 07:48
It is deleted in handleThreadFinished slot via deleteLater. I don't close the application in one second, so the thread has enough time to finish. Actually, in this very case I don't really care of thread deletion, I just don't understand why does isRunning return true when finished signal is already emitted.