Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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:

    1. I close the main window and the thread should also be terminated
    2. 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?


  • Moderators

    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's quitslot



  • 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's quitslot

    Same for this one. If I quit the main application on the 'finished' signal, is the destructor of the QThread still executed properly?


  • Lifetime Qt Champion

    @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.


  • Lifetime Qt Champion

    @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.


  • Moderators

    @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 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.



  • 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?


Log in to reply