【问题标题】:When or how to delete QThread in Qt何时或如何在 Qt 中删除 QThread
【发布时间】:2015-01-27 05:07:44
【问题描述】:

我从here 找到了这个 QThread 示例。建议使用 QObject 和 QThread 而不是子类化 QThread。

class Worker : public QObject
{
   Q_OBJECT

public slots:
    void doWork() {
        /* ... */
    }
};

QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);

我的第一个问题是何时以及如何删除线程?

我已尝试将完成连接到 2 个插槽,myTest 和 deleteLater。我在 myTest 中设置了一个断点,这从未被触发。所以我怀疑没有finished信号,这意味着线程不会被删除。

connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(myTest()));

对于工作对象,我发出完成信号作为 doWork 中的最后一条指令,并将其连接到可以删除工作对象的插槽。这是正确的方法吗?

Qt 版本:4.6.2

【问题讨论】:

  • 只需将线程finished()信号先连接到worker,再连接到线程自己的deleteLater()
  • 必须告诉线程quit,否则它永远不会发出finished 信号。
  • Ops,我的最后一条评论似乎只适用于 4.8 之后的 Qt 版本,它可能不适用于 4.6.2。
  • doWork 函数结束时在Worker 中发出一些信号,并在连接完成之前将其连接到线程的quit() 槽到deleteLater() 等

标签: windows multithreading qt


【解决方案1】:

您的线程在其worker 方法执行完成时正常退出,但是如果您想在线程退出时做一些事情,请使用finished() 信号,并且可以释放刚刚结束的线程中的对象,通过将finished() 信号连接到QObject::deleteLater()

connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);

【讨论】:

    【解决方案2】:

    您稍后使用connect() 语句删除thread 的方法应该有效。

    您建议的在 worker 之后删除 finished() 的方法也应该有效。

    但是,为了触发您的插槽myTest(),您需要添加更多代码:

    1. workerfinished() 时,使用connect() 语句调用thread->quit()worker->deleteLater()this->deleteLater()
    2. 在上述connect() 语句中使用Qt::DirectConnection

    以下是实现上述方案的测试示例,假设你的类名为Tester

    文件worker.h

    #ifndef WORKER_H
    #define WORKER_H
    
    #include <QObject>
    
    class Worker : public QObject
    {
    Q_OBJECT
    public:
        Worker();
        ~Worker();
    signals:
        void finished();
    public slots:
        void doWork();
    };
    
    #endif // WORKER_H
    

    文件worker.cpp

    #include "worker.h"
    
    #include <QDebug>
    
    Worker::Worker()
    {
        qDebug() << "D/Worker==Worker";
    }
    
    Worker::~Worker()
    {
        qDebug() << "D/Worker==~Worker";
    }
    
    void Worker::doWork()
    {
        qDebug() << "D/Worker==doWork";
    
        // Do work here
    
        emit finished();
    }
    

    文件tester.h

    #ifndef TESTER_H
    #define TESTER_H
    
    #include <QObject>
    
    class Tester : public QObject
    {
        Q_OBJECT
    public:
        Tester();
        ~Tester();
    public:
        void startTesting();
    public slots:
        void myTest();
    };
    
    #endif // TESTER_H
    

    文件tester.cpp

    #include "tester.h"
    
    #include "worker.h"
    
    #include <QThread>
    #include <QDebug>
    
    Tester::Tester()
    {
        qDebug() << "D/Tester==Tester";
    }
    
    Tester::~Tester()
    {
        qDebug() << "D/Tester==~Tester";
    }
    
    void Tester::startTesting()
    {
        qDebug() << "D/Tester==startTesting";
    
        QThread * thread = new QThread;
        Worker * worker = new Worker;
        worker->moveToThread(thread);
        connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()), Qt::DirectConnection);
        connect(thread, SIGNAL(finished()), this,   SLOT(myTest()),      Qt::DirectConnection);
        connect(worker, SIGNAL(finished()), thread, SLOT(quit()),        Qt::DirectConnection);
        connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()), Qt::DirectConnection);
        connect(worker, SIGNAL(finished()), this,   SLOT(deleteLater()), Qt::DirectConnection);
        thread->start();
        QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
    
        // "thread" is deleted later.
        // "worker" is deleted later.
    }
    
    void Tester::myTest()
    {
        qDebug() << "D/Tester==myTest";
    }
    

    文件main.cpp

    #include <QCoreApplication>
    #include <QObject>
    #include <QDebug>
    
    #include "worker.h"
    #include "tester.h"
    
    int main(int argc, char *argv[])
    {
        qDebug() << "D/TestQThreadNewDelete==main";
    
        QCoreApplication a(argc, argv);
    
        Tester * tester = new Tester;
    
        tester->startTesting();
    
        // "tester" is deleted later in tester->onWorkerFinished().
    
        return a.exec();
    }
    

    在 Linux 上使用 Qt 5.5.0 运行此测试应用程序的输出如下:

    D/TestQThreadNewDelete==main
    D/Tester==Tester
    D/Tester==startTesting
    D/Worker==Worker
    D/Worker==doWork
    D/Tester==myTest
    D/Worker==~Worker
    D/Tester==~Tester
    

    从中我们可以看出:

    1. 插槽Tester::myTest() 已触发。
    2. 因此,信号 QThread::finished() 应该更早发出。
    3. 同样,插槽QThread::deleteLater() 也会被触发。这很可能在测试应用程序退出时发生。但是,需要调试才能确认这一点,我没有尝试过。

    【讨论】:

    • 最后一次连接 Qt::DirectConnection 是错误的,会导致你的应用崩溃,因为 Tester 会在子线程中被销毁。不要乱用 DirectConnection 和线程。
    • 你是对的。我没有通过每一行检查的错误。所以不要在最后一个connect 语句中使用Qt::DirectConnection。感谢您指出这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-29
    • 1970-01-01
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多