Correctly terminating continuous, threaded application
-
I have a QGUIApplication/ QQmlApplicationEngine and a continuously running QThread. The QThread is the interface between the GUI and hardware (a ROS node). Since the GUI and the QThread are always necessary, I'm wondering how to terminate both of them correctly in case one of them is terminated. I'm thinking about two situations:
- I close the main window and the thread should also be terminated
- The thread crashes or is terminated (e.g. Ctrl+Z in terminal) and this should also terminate the GUI application
So what I did up to now:
First case:
My QThread has the following destructor:
QROSNode::~QROSNode() { if(ros::isStarted()) { ros::shutdown(); // this allows ros::spin() to quit and finish run() ros::waitForShutdown(); } wait(); }
Are the QThreads terminated like normal class objects and the destructor called if the main application is stopped? Why is 'wait()' needed and is it the correct way?
Second case:
This is my main() function:
int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); // init application ros_node::QThread qthread(argc, argv); // create ROS node thread 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); return app.exec(); // execute event loop }
How can I shut down the main application if the QThread is terminated? Can I emit a signal in the QThread destructor which somehow terminates my main application?
-
hi @prex and welcome
Signals and Slots are also here you friend :)
QApplication has a
aboutToQuit
signal, that should be emitted when you close your last open window (with default settings)Connect that to your thread and call
quit
on it.Same for your QThread. Connect the threads
finished
signal to QApplication'squit
slot -
Hi J-Hilk and thanks for your response.
QApplication has a
aboutToQuit
signal, that should be emitted when you close your last open window (with default settings)Connect that to your thread and call
quit
on it.Does this mean that if I don't call quit, the QThread continues running? Does quit() call my destructor since I need to shut down my interface correctly?
Same for your QThread. Connect the threads
finished
signal to QApplication'squit
slotSame for this one. If I quit the main application on the 'finished' signal, is the destructor of the QThread still executed properly?
-
@prex said in Correctly terminating continuous, threaded application:
If I quit the main application on the 'finished' signal, is the destructor of the QThread still executed properly?
Yes, because you allocated it on the stack.
-
@jsulm said in Correctly terminating continuous, threaded application:
@prex said in Correctly terminating continuous, threaded application:
If I quit the main application on the 'finished' signal, is the destructor of the QThread still executed properly?
Yes, because you allocated it on the stack.
Ok, thanks! But then I don't understand why I need to quit my thread explicitly if the main application is terminated and the object goes out of scope anyway.
-
@prex said in Correctly terminating continuous, threaded application:
object goes out of scope anyway
the objects yes, but not necessarily the thread which is handled by the object. It is always a good idea to terminate threads in a clean way.
-
@prex said in Correctly terminating continuous, threaded application:
@jsulm said in Correctly terminating continuous, threaded application:
@prex said in Correctly terminating continuous, threaded application:
If I quit the main application on the 'finished' signal, is the destructor of the QThread still executed properly?
Yes, because you allocated it on the stack.
Ok, thanks! But then I don't understand why I need to quit my thread explicitly if the main application is terminated and the object goes out of scope anyway.
I'm not so sure about that, I haven't checked the source code, so I behold judgment :)
But it's good form anyway.
Take a look at the official Thread Examplehttps://doc.qt.io/qt-5/qthread.html#details
Even so the Thread object should get cleaned up automatically (its a member variable on the stack) quit and wait are still called.
-
So I added these two connections:
QObject::connect(&qrosnode, SIGNAL(finished()), &app, SLOT(quit()), Qt::QueuedConnection); QObject::connect(&app, SIGNAL(aboutToQuit()), &qrosnode, SLOT(quit()), Qt::QueuedConnection);
Take a look at the official Thread Example
https://doc.qt.io/qt-5/qthread.html#details
Even so the Thread object should get cleaned up automatically (its a member variable on the stack) quit and wait are still called.
Should I use 'deleteLater()'? Why not just putting 'quit()' and 'wait()' in each QThread destructor?