I am trying to perform some work in a separate thread and stop that thread when the work is done.
I have set up a connection like this
thread.connect( workerClass, SIGNAL( finished() ), SLOT( quit() ) );
but the quit() slot is never called when I emit the finished() signal. The command line does not show any warnings related to failed connections.
I created a simple test project to narrow down the problem and I get the same behavior:
TestClass.h:
#ifndef TESTCLASS_H
#define TESTCLASS_H
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass() { }
signals:
void finished();
public slots:
void doWork();
}
#endif // TESTCLASS_H
TestClass.cpp:
#include "TestClass.h"
#include <QtCore/QDebug>
void TestClass::doWork()
{
qDebug() << "Starting";
for( long i = 0; i < 1000000000; i++ );
qDebug() << "Done";
emit finished();
};
and the main.cpp:
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include "TestClass.h"
int main( int argc, char* argv[] )
{
QCoreApplication a( argc, argv );
TestClass testClass;
QThread testThread;
testClass.moveToThread( &testThread );
testThread.connect( &testClass, SIGNAL( finished() ), SLOT( quit() ) );
testClass.connect( &testThread, SIGNAL( started() ), SLOT( doWork() ) );
testThread.start();
testThread.wait();
return 0;
}
So here is what I expected to happen:
- Once
testThread.start()
gets processed, the thread'srun()
function gets called, which internally callsexec()
and starts an event loop. Additionally it throws astarted()
signal. testClass
has itsdoWork()
slot called.- When
TestClass::doWork()
is done, it throws afinished()
signal. - The event loop of
testThread
receives the signal and forwards it to itsquit()
slot testThread.wait()
returns from waiting as the thread has ended.
Steps 1-3 work and I get the qDebug()
output.
The problem is at step 4: The signal is fired and forwarded to some event loop (I debugged it a bit, but couldn't figure out to which event loop it was fired) but the quit()
slot is never called.
What am I doing wrong?
P.S.: Please don't suggest subclassing QThread instead, the whole point of me trying this way out is because I want to avoid subclassing QThread.
I believe the issue is that you actually don't have Qt event loop running in the scenario. If you replace
testThread.wait()
witha.exec()
(which starts the Qt event loop) you should see your signals/slots getting processed properly.If you want the application to quit when your thread has finished you can use QCoreApplication's
quit()
slot to do so.I had the same problem and found the answer. Here is my question: What is the use of QThread.wait() function?
To solve your problem, you don't need to run the a.exec(), what you need to do is, instead of invoking the quit() which tries to send a signal to your application's event loop (which apparently doesn't exist), you have to call it directly.
So for your code, drop the line:
And instead of:
Use:
Tada... problem solved. Lesson learned: don't try to exit a worker thread by the qt signal-slot mechanism from within it, because your signals do not end up where they are supposed to (your worker thread's event loop), but they end up in the creating thread instead. You never know what that thread is doing, and if its event loop is running or not, and this shouldn't be of business to your worker thread anyways... Instead, call the quit directly.