terminating a thread



  • Hi, all -

    I've got a small application with a worker thread that runs in a loop. I'd like to terminate the worker thread (and stop the application) when the user pushes a quit button.

    Here's what I've got so far:

    class Worker : public QThread
    {...}
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget widget;
        Worker worker;
    
        QObject::connect(&widget, &Widget::quitButtonPushed, &worker, &Worker::quit);
    

    But I now see that the quit() call only affects an event loop within a thread, not the actual thread itself.

    So, how do I properly shut down the thread before exiting the application?

    Thanks...


  • Lifetime Qt Champion

    Hi,

    Do you mean you have in infinite loop in the run of your thread ?



  • Yes...it reads from a socket, and when it gets something, passes it to the display widget.


  • Lifetime Qt Champion

    In that case, make the loop stoppable:

    void MyThread::stop()
    {
        continue.deref();
    }
    void MyThread::run() 
    {
       continue.ref();
        while(continue) {
            /// Do your stuff
        }
    }
    

    continue being a QAtomicInt.

    You can then call stop in your application, then QThread::wait() to ensure its finished before continuing.



  • Interesting. So, MyThread::stop would be a slot to receive the signal from the display widget? Would MyThread::run then send a signal to the QApplication prior to exiting? And if so, is there concern for a race condition under which the Application might try to exit before the thread has terminated?


  • Lifetime Qt Champion

    No there's no signal emitted since you implement your own version of run. Note that you can send a signal yourself if you need/want to. The call to wait after the call to stop is where you ensure that your thread stops before you continue with your application.



  • @SGaist OK, I understand the mechanics of the worker thread, but how to invoke the wait is a bit of a mystery. Here's my main:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget widget;
        Worker worker;
    
        QObject::connect(&worker, &Worker::newResponseText, &widget, &Widget::addText);
        QObject::connect(&widget, &Widget::quitButtonPushed, &worker, &Worker::doQuit);
    
        widget.show();
        worker.start();
        return a.exec();
    }
    

    I don't see:

    • where to put the wait(), given that a.exec() runs infinitely.
    • how to terminate the application (worker::run() could send a signal after it exits its loop, I suppose).

  • Lifetime Qt Champion

    You could use a lambda that calls doQuit and then wait rather than than connecting doQuit directly. Or you can integrate wait in doQuit.

    Add a signal to your Worker class that you emit at the end of the loop.


  • Qt Champions 2017

    @mzimmers said in terminating a thread:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget widget;
        Worker worker;
    
        QObject::connect(&worker, &Worker::newResponseText, &widget, &Widget::addText);
    
        // Invoke directly as there's no running event loop to process the slot
        QObject::connect(&widget, &Widget::quitButtonPushed, &worker, &Worker::doQuit, Qt::DirectConnection);
        // Connect the aboutToQuit from the `QCoreApplication` so you don't hang when the button's not pressed
        QObject::connect(&a, &QCoreApplication::aboutToQuit, &worker, &Worker::doQuit, Qt::DirectConnection);
    
       widget.show();
       worker.start();
    
        // Store the return value and then wait for the thread to exit
        int retValue = QApplication::exec();
        worker.wait();
        // After the thread has finished, return from main()
        return retValue;
    }
    

    This is all assuming doQuit is what @SGaist wrote - raising an atomic flag to tell the thread to quit.

    Btw, you can use QThread::requestInterruption and QThread::isInterruptionRequested instead of rolling your own.



  • @SGaist so my worker thread will signal the QApplication, so that the QApplication can quit. Correct?

    I'm still lost regarding the use of wait(). It can't reside in the worker object, as a thread can't wait for itself. And I have no context from which to use it in main(). Do I need a parent class/object for my worker?


  • Lifetime Qt Champion

    See @kshegunov's excellent alternative.



  • @kshegunov so, do I correctly understand that, in your example, the QApplication will terminate before the worker thread?

    I didn't know you could do that...


  • Qt Champions 2017

    You can exit the (main) event loop at any time you want, you need to wait before returning from main() so your process doesn't terminate before the thread has done so. So yes, you can exit the loop before returning from main(). :)

    PS.
    QCoreApplication::exec does practically nothing, it's a convenience function, you can substitute it with:

    QEventLoop loop;
    return loop.exec();
    


  • @kshegunov well, isn't that something. Very nice.

    I implemented it a bit differently from your example:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget widget;
        Worker worker;
        int rc;
    
        QObject::connect(&worker, &Worker::newResponse, &widget, &Widget::addText);
        QObject::connect(&widget, &Widget::quitButtonPushed, &worker, &Worker::doQuit);
        QObject::connect(&worker, &Worker::reachedEndOfThread, &a, &QApplication::exit);
    
        widget.show();
        worker.start();
        rc = a.exec();
        worker.wait();
        return rc;
    }
    
    Seems to work fine. Thanks, guys.
    

  • Qt Champions 2017

    You should still connect the aboutToQuit signal, as you may click the x in the top right of the window, which wouldn't trigger your doQuit.



  • Done. Thanks again.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.