Search code examples
c++qtqthread

How to quit the event loop of a worker QThread


I'm writing an application with a button to start/stop a worker thread (which implements QThread). The worker thread keeps scheduling a job every few milliseconds. To terminate the worker thread, I'm calling worker.quit() (worker.exit(0) doesn't work either) method from the GUI thread and waiting the finished signal to be fired.

The problem is that even though the finished signal is fired, the thread isn't terminated.

Here is a minimal example: https://gist.github.com/NawfelBgh/941babdc011f07aa4ab61570d7b88f08

screenshot of the minimal example

Edit

My interpretation of what happened was wrong: The worker thread was being terminated but the method iter was getting executed in the main thread as said by @sergey-tachenov and as confirmed from the logging generated with the code:

void run() {
    std::cout <<"From worker thread: "<<QThread::currentThreadId() << std::endl;
...
void iter() {
    std::cout <<"From thread: "<<QThread::currentThreadId() << std::endl;
...
void MainWindow::on_pushButton_clicked()
{
    std::cout <<"From main thread: "<<QThread::currentThreadId() << std::endl;

I switched to a different design which doesn't rely on QTimers. But I didn't submit it as an answer since the title of this question is "How to quit the event loop of a worker QThread".


Solution

  • The thread is terminated. Only your timer runs not in the thread you've started but in the main thread, that's why it isn't stopped. This is because it uses queued connections by default and the thread object lives in the thread in which it was created which is the main thread. To fix it:

    • Do not subclass QThread. It's usually a bad idea unless you want to actually extend QThread's functionality.
    • Create a separate worker object that inherits QObject.
    • Use moveToThread to move the worker object to the created thread. It will cause all its slots to fire actually in the thread. If you use default or queued connections, that is.

    The QThread docs provide an excellent example on that (the first one).

    Note that if you actually want to use data provided by the thread to update GUI, you'll have to somehow correctly publish that data to the GUI thread (possibly using emit and queued connections) instead of trying to update GUI directly from the thread. And if you want to access shared data, you probably need to guard it with a QMutex, not like you do with your shared counter.