Qt GUI 与 QThread 中的 worker 一起挂起

Qt GUI hanging with worker in a QThread

我有一个工人需要完成一个任意阻塞任务

class Worker : public QObject
{
    Q_OBJECT;

public:
    using QObject::QObject;

public slots:
    void start()
    {
        for (int i = 0; i < 10; i++)
        {
            qDebug("I'm doing work...");
            Sleep(1000);
        }
    }
};

在我的 MainWindow 构造函数中,我这样开始任务:

class MainWindow : public QWidget
{
    Q_OBJECT;

public:
    explicit MainWindow(QWidget* parent = nullptr) : QWidget(parent)
    {
        QThread* t = new QThread(this);
        Worker* w = new Worker(this);
        w->moveToThread(t);

        this->connect(
            t, &QThread::started,
            w, &Worker::start
        );
        this->connect(
            t, &QThread::finished,
            t, &QThread::deleteLater
        );

        t->start();
    }
};

我的切入点:

int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    MainWindow mainWindow{};
    mainWindow.show();

    return app.exec();
}

当我 运行 程序时,我只是得到一个旋转的鼠标圈,并且 window 内容直到 10 秒后才加载(当工作人员完成时)。为什么会这样?我需要做什么才能使 Worker::start 在后台 运行 而不影响 GUI?

P.S. 我正在使用 Qt 6.2.2 和 Windows 11,但我非常怀疑这与此问题有任何关系。

问题是 worker 实际上并没有移动到线程(不是写入控制台的警告吗?我敢打赌是。),因为它的父实例,即 MainWindow 实例仍在 GUI 中线程。

移动到线程时,只能通过移动最顶层的父对象来移动对象的整个层次结构。您不能让父线程与其子线程处于不同的线程中。

您应该创建没有父级的工人。

Worker* w = new Worker();

当然你也应该在你的 Worker class.

中添加一些 finished() 信号
class Worker : public QObject
{
    Q_OBJECT;

public:
    using QObject::QObject;

    void start()
    {
        for (int i = 0; i < 10; i++)
        {
            qDebug("I'm doing work...");
            Sleep(1000);
        }
        emit finished();
    }

signals:
    void finished();
};

并添加这些连接:

this->connect(
            w, &Worker::finished,
            t, &QThread::quit
        ); 
this->connect(
            t, &QThread::finished,
            w, &Worker::deleteLater
        );

否则你线程的even循环不会结束,worker也不会被删除