简体   繁体   中英

Calling quit in destructor doesn't kill the QThread?

I run this code through QtCreator.
Problem is that when I close the output window the thread doesn't die. To kill the thread I have to go to the terminal and kill it manually by finding its ID or use red square button on Application output window to kill it.

This application is supposed to be running forever unless we press Alt F4 to close the window.

Source file [cpp]:

#include "mainwindow.h"

Controller::Controller(QMainWindow *parent) : QMainWindow(parent)
{
    worker_obj.moveToThread(&workerThread);
    worker_obj.timerReceivePackets.moveToThread(&workerThread);

    connect(this, &Controller::operate, &worker_obj, &Worker::doSomething);

    connect(&workerThread, SIGNAL(started()), &worker_obj, SLOT(initialize()));

    connect(&worker_obj, &Worker::resultReady, this, &Controller::handleResults);

    connect(&workerThread, SIGNAL(finished()), &workerThread, SLOT(deleteLater()));

    workerThread.start();
}

Controller::~Controller()
{
    workerThread.wait();
    workerThread.quit();
    workerThread.terminate();
}

Header [h]

#ifndef Worker_H
#define Worker_H

#include <QMainWindow>
#include <QObject>
#include <QImage>
#include <QDebug>
#include <QThread>
#include <QTimer>

class Worker : public QObject
{
    Q_OBJECT

private:
public:

    QTimer timerReceivePackets;

    Worker(QObject * parent = 0) {}
    ~Worker() {}

public slots:
    void initialize()
    {
        connect (&timerReceivePackets, SIGNAL (timeout()),
                 this, SLOT (doSomething()));

        timerReceivePackets.start();
    }

    void doSomething()
    {
        while(1)
        {
            QString result;
                /* ... here is the expensive or blocking operation ... */
            emit resultReady(result);
        }
    }

signals:
    void resultReady(const QString &result);
};

class Controller : public QMainWindow
{
    Q_OBJECT
    QThread workerThread;

public:
    Worker worker_obj;

    Controller( QMainWindow *parent = 0 );
    ~Controller();

public slots:
    void handleResults(const QString &) {}

signals:
    void operate(const QString &);

};

#endif // Worker_H

Below is a solution using QWidget::closeEvent to ask worker to finish its task. Immediate window close (application quit when main window is in question) is ignored to terminate thread gracefully and application is exited only after the worker has finished. This makes it possible to save the state of the expensive operation done in the thread before application is exited. After worker has finished QObject::deleteLater is called for worker, and QThread::quit for the thread which triggers deleteLater for the thread after it's fully shut down.

Controller:

class Controller : public QMainWindow
{
    Q_OBJECT
public:
    explicit Controller(QMainWindow *parent = nullptr)
        : QMainWindow(parent), m_worker(new Worker)
    {
        QThread *thread = new QThread;
        m_worker->moveToThread(thread);
        connect(thread, &QThread::started, m_worker, &Worker::operate);
        connect(m_worker, &Worker::resultReady, this, &Controller::handleResults);
        connect(m_worker, &Worker::finished, thread, &QThread::quit);
        connect(thread, &QThread::finished, thread, &QObject::deleteLater);
        connect(m_worker, &Worker::finished, m_worker, &QObject::deleteLater);
        connect(m_worker, &Worker::finished, qApp, &QApplication::quit);
        thread->start();
    }

    virtual ~Controller() {}

public slots:
    void handleResults(const QString &result){
        qDebug() << result;
    }

protected:
    void closeEvent(QCloseEvent *event) override
    {
        m_worker->finish();
        event->ignore();
    }

private:
    Worker *m_worker;
};

Worker:

class Worker : public QObject
{
    Q_OBJECT

public:
    explicit Worker(QObject *parent = nullptr)
        : QObject(parent), m_continue(false) {}
    virtual ~Worker() {}

public slots:
    void operate(){
        m_continue = true;
        static QString result;
        while(m_continue)
        {
            result.append('a');
            QThread::sleep(2);
            emit resultReady(result);
        }
        emit finished();
    }

    void finish() {
        m_continue = false;
    }

signals:
    void finished();
    void resultReady(const QString &result);

private:
    bool m_continue;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM