首页 > 解决方案 > 在另一个 QThread 上运行成员方法时,无法将事件发送到不同线程拥有的对象

问题描述

我需要在我的 MainWindow 类中运行一个方法,在不同的线程中,因为它是一个耗时的过程。

这是我尝试过的:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    initGui(ui);

    // Create background worker thread
    backgroundWorker = QThread::create([this] {
        backgroundMethod();
    });

    // Define when finished with work
    connect(backgroundWorker, &QThread::finished, [this] () {
        qDebug() << "Background method has finished";

        // Stop movie
        ui->lblLoading->movie()->stop();

        // go to next screen
        ui->tabbarMainWidget->tabBar()->setCurrentIndex(1);

        //show backup icon files
        if(filesToBackup.size() > 0) {
            qDebug() << "There are files to backup!";
            ui->lblInfoImage->show();
        }
    });

    // Start worker thread
    backgroundWorker->start();
}

背景方法

void MainWindow::backgroundMethod() {
    for (int i = 0; i < 10; i++) {
        qDebug() << "Hello World";
    }
}

我省略了很多代码,因为它不是必需的。基本逻辑如下:

  1. 使用QThread::create()启动新线程

  2. 运行backgroundMethod()直到完成,同时让 UI 可用于其他工作。

  3. 完成backgroundMethod()后,QThread应该发出finished()信号。

  4. 我在backgroundWorker线程finished()和 lambda 之间建立了一个连接设置来运行更多代码。

问题:

后台方法已完成

QObject::killTimer:定时器不能从另一个线程停止

QCoreApplication::sendEvent 中的 ASSERT 失败:“无法向其他线程拥有的对象发送事件。当前线程 0x0x2801d950。接收器 'lblInfoImage'(类型为 'QLabel')在线程 0x0x2688c4b0 中创建”,文件 kernel\qcoreapplication.cpp,行578 04:11:28:程序意外结束。

简而言之,我正在访问lblInfoImage线程backgroundWorker。我知道使用信号/插槽机制应该可以解决这个问题,我对它的使用是正确的。

我不确定为什么会发生这种情况,我需要一些帮助来了解我做了什么导致问题以及如何解决它

标签: c++multithreadingqtsignals-slotsqthread

解决方案


问题很简单:您在非 UI 线程上执行 UI 代码,这在 Qt(以及许多其他跨不同语言的 UI 框架中)是严格禁止的。发生这种情况是因为您连接错误:

connect(backgroundWorker, &QThread::finished, [this] () {
    ...
});

该连接意味着:每当QThread发出finished信号时运行此功能。问题是,它将在发出的信号的上下文中运行函数,这是另一个线程不是线程backgroundWorker所在的线程。所以你必须提供 UI 线程上下文来接收这个信号:

connect(backgroundWorker, &QThread::finished, this, [this] () {
        ...
    });

现在提供的函数将在 UI 线程 ( this) 的上下文中执行。


推荐阅读