PDA

View Full Version : QThread doesn't emit finished() signal when quit() or exit() slots are called



stefanadelbert
6th April 2011, 06:30
I have MyService (derived from QtService<QCoreApplication>) which has a MyThread (derived from QThread). MyThread::run() creates a QTcpServer and called exec(). I'm on Windows 7 using Qt 4.6.2.

In MyService::start() I call MyThread::start(). QThread::started() is emitted by MyThread.

In MyService::stop() I call MyThread::quit(). I would expect QThread::finished() to be emitted by MyThread, but it isn't.

If I call MyThread::terminate() from MyService::stop(), I get both QThread:finished() and QThread:terminated().

Should I be expecting QThread:finished() to be emitted? The documentation says the following:


void QThread::finished () [signal]
This signal is emitted when the thread has finished executing.

See also started() and terminated().

Maybe the thread only emits QThread::finished() if it finishes of its own accord, i.e. not by having its quit() or exit() functions called.

Added after 10 minutes:

Interesting...

I have just commented out the call to exec() from MyThread::run(). MyThread::run() returns straight away (it doesn't do anything now) and QThread::finished() is emitted.

I take from this that one should not expect to get QThread::finished() when calling QThread::quit() or QThread::exit(). QThread::finished() is only emitted if the thread finishes of its own accord or QThread::terminate() is called. If QThread::terminate() is called, both QThread::finished() and QThread::terminated() are emitted.

This does make sense. If you're calling QThread::quit() or QThread::exit() explicitly, you're assuming control and shouldn't need the thread to tell you that it's finished because you're telling it to finish.

Anyone got anything to add?

wysota
6th April 2011, 10:55
Yes, I have something to add - you're wrong, the signal gets emitted.


#include <QtCore>

class Test : public QObject {
Q_OBJECT
public:
Test(){}
public slots:
void onFinished() {
qDebug() << Q_FUNC_INFO;
}
};

#include "main.moc"

int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
QThread thread;
Test test;
QObject::connect(&thread, SIGNAL(finished()), &test, SLOT(onFinished()));
thread.start(); // calls "exec()"
QTimer::singleShot(1000, &thread, SLOT(quit()));
return app.exec();
}


./tth
void Test::onFinished()

stefanadelbert
7th April 2011, 01:24
Wysota, in my case QThread::finished() is not being emitted when QThread::quit() is called from QtService::stop(). Or more specifically, the slot I have connected to QThread::finished() is not being called if I call QThread::quit() from QtService::stop(). That doesn't mean that the signal isn't being emitted by QThread. Maybe something else is causing this signal not to be handled. Maybe the signal is on a queue somewhere and being handled too late.

I tried your example and I can confirm that in that case the QThread::finished() IS being emitted, as expected. Your example is simpler that mine in that you don't deal with a QtService.

I tried replacing MyThread with a QThread in my example, but I still get the same behaviour - QThread::finished() is not emitted when QThread::quit() is called from QtService::stop().

However, if I set a timer (as in your example) to call QThread::quit() rather than call it from QtService::stop(), QThread::finished() is emitted and handled correctly!

Anyone for anything to add?

wysota
7th April 2011, 12:09
Wysota, in my case QThread::finished() is not being emitted when QThread::quit() is called from QtService::stop().
QThread doesn't care whether quit() is called from QtService or anything else. The signal is emitted.


Or more specifically, the slot I have connected to QThread::finished() is not being called if I call QThread::quit() from QtService::stop().
That might indeed be true.

That doesn't mean that the signal isn't being emitted by QThread.
Well... that's what you said previously - that QThread doesn't emit finished() when quit() is called.


Maybe the signal is on a queue somewhere and being handled too late.
If you quit the application right away then that's indeed the case. The signal is queued and will be delivered when the calling thread processes its events.