QThread does not quit, why?
-
Hi,
I am using a QThread and it works fine besides that it does not quit.
QThread myThread; QObject::connect(&app, &QApplication::aboutToQuit, myCtrl, &Control::deleteLater); QObject::connect(myCtrl, &Control::finished, &myThread, &QThread::quit); QObject::connect(&myThread, &QThread::finished, &myThread, &QThread::deleteLater); myCtrl->moveToThread(&myThread); myThread.start(); //Debug: QSignalSpy spy(myCtrl, &Control::finished); //Count was checked later and signal was emitted correct.
The quit process I start with the "QApplication::aboutToQuit()"-signal. This calls the destructor of my class which looks like this:
Control::~Control() { qDebug() << "ControlDTOR called!"; emit finished(); }
I see that the destructor was called and also the finished signal was emitted.
However, "myThread.wait()" never returns.What could be the reason for this and how can I make it quit in a proper way?
Thanks!
-
Please show us the whole piece of code. You're probably blocking the event loop ... edit: or your thread just goes out of scope ...
-
Thanks,
I now made a MWE:
main.cpp:
#include <QApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QThread> #include <control.h> //Debug: #include <QDebug> int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); QApplication::setOrganizationName("a"); QApplication::setOrganizationDomain("b"); QApplication::setApplicationName("c"); Control* myControl = new Control(); QThread myThread; QObject::connect(&app, &QApplication::aboutToQuit, myControl, &Control::deleteLater); QObject::connect(myControl, &Control::finished, &myThread, &QThread::quit); QObject::connect(&myThread, &QThread::finished, &myThread, &QThread::deleteLater); myControl->moveToThread(&myThread); myThread.start(); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); int exitCode = app.exec(); qDebug() << "Started Waiting:"; myThread.wait(); // Wait for thread to quit qDebug() << "Quit"; // This is never reached as myThread.wait() blocks forever. return exitCode; }
control.h:
#ifndef CONTROL_H #define CONTROL_H #include <QObject> #include <QDebug> class Control : public QObject { Q_OBJECT public: explicit Control(QObject *parent = nullptr); ~Control(); signals: void finished(); }; #endif // CONTROL_H
control.cpp:
#include "control.h" Control::Control(QObject *parent) : QObject(parent) { } Control::~Control() { qDebug() << "Control DTOR called!"; emit finished(); }
Output after closing the QML window:
Started Waiting: Control DTOR called!
-
@robro said in QThread does not quit, why?:
QObject::connect(&myThread, &QThread::finished, &myThread, &QThread::deleteLater);
This will crash since your thread is on the stack.
-
Hi,
I understand.
I tried the following, but the thread does still not end:QThread *myThread = new QThread(); QObject::connect(myControl, &Control::finished, myThread, &QThread::quit); QObject::connect(myThread, &QThread::finished, myThread, &QThread::deleteLater);
What is the problem?
-
@robro The solution is
QObject::connect(myControl, &Control::finished, myThread, &QThread::quit, Qt::DirectConnection);
The reason is, when the
Control::finished
signal is emitted, the myControl object lives in the new thread, but the myThread object lives in the main thread, even though it is a thread object.
(EDITED)
So when you use the default connection type (Qt::AutoConnection
), and the receiver does not live in the thread that emits the signal,Qt::QueuedConnection
will be used.
That means(from the doc):The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
But when your signal is emitted, the application is about to quit the main event loop, aka, the event loop of the receiver's thread. So the slot will never be invoked.
-
@Bonnie said in QThread does not quit, why?:
The solution is
QObject::connect(myControl, &Control::finished, myThread, &QThread::quit, Qt::DirectConnection);
And where does it say that this slot is thread-safe?
@robro
Just quit the thread before you exit the application.QObject::connect(&app, &QApplication::aboutToQuit, myCtrl, &Control::deleteLater); QObject::connect(myCtrl, &Control::finished, &myThread, &QThread::quit); QObject::connect(&myThread, &QThread::finished, myCtrl, &Control::deleteLater); //< This is needed
Which translates simply to:
qDebug() << "Started Waiting:"; myThread.quit(); myThread.wait(); // Wait for thread to quit qDebug() << "Quit";