You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt线程间数据传递问题:worker的doWork()函数无法启动

问题分析与解决方案

核心问题点

  • 线程使用逻辑错误:你的MyThreadWorker继承了QThread,同时又调用moveToThread将其移到另一个QThread实例中,违背Qt线程设计逻辑——QThread是线程管理者,而非工作对象,正确Worker应继承QObject。
  • 线程启动方式错误:主窗口中调用worker->start(),但worker已被移到子线程,且你重写的start方法并非线程启动的正确路径,应启动thread->start()来触发线程started信号。
  • 方法重写冲突:继承QThread后重写start会覆盖父类的线程启动方法,导致线程无法初始化事件循环,QTimer因此无法工作。

推荐解决方案:Worker继承QObject(官方标准写法)

这种模式逻辑清晰、易于维护,是Qt官方推荐的线程工作方式。

1. 修改Worker头文件

#include <QObject>
#include <QTimer>

class MyThreadWorker : public QObject
{
    Q_OBJECT

public:
    float x;
    float y;
    float z;
    int correct;

    explicit MyThreadWorker(QObject *parent = nullptr);

private:
    Adafruit_BNO055 * imu_first;
    QTimer * timer;

signals:
    void dataReady(float x, float y, float z, int correct);

public slots:
    void doWork();
    void startWork(); // 自定义启动槽,避免和QThread的start方法冲突
    void stopWork(); // 可选:添加资源清理逻辑
};

2. 修改Worker源文件

#include "MyThreadWorker.h"

MyThreadWorker::MyThreadWorker(QObject *parent) : QObject(parent)
{
}

void MyThreadWorker::startWork()
{
    imu_first = new Adafruit_BNO055;
    imu_first->imu_initialization();

    timer = new QTimer(this); // 指定父对象,自动管理内存
    connect(timer, &QTimer::timeout, this, &MyThreadWorker::doWork);
    timer->start(1000);
    qDebug() << "start work in thread";
}

void MyThreadWorker::doWork()
{
    imu_first->sig_bno_handler();
    gpioSleep(0, 0, 1000);
    imu_first->savevector();
    
    x = imu_first->myStruct.x;
    y = imu_first->myStruct.y;
    z = imu_first->myStruct.z;
    correct = imu_first->init_correct;
    qDebug() << "Dane: " << x;

    emit dataReady(x, y, z, correct);
}

void MyThreadWorker::stopWork()
{
    if(timer){
        timer->stop();
        delete timer;
        timer = nullptr;
    }
    delete imu_first;
    imu_first = nullptr;
}

3. 修改主窗口源文件

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化线程与Worker
    QThread* thread = new QThread(this);
    MyThreadWorker* worker = new MyThreadWorker();
    worker->moveToThread(thread);

    // 连接信号槽
    connect(thread, &QThread::started, worker, &MyThreadWorker::startWork);
    connect(worker, &MyThreadWorker::dataReady, this, &MainWindow::updateData);
    // 线程结束时自动清理资源
    connect(thread, &QThread::finished, worker, &QObject::deleteLater);
    connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    // 启动线程(关键:启动的是thread实例,而非worker)
    thread->start();

    // 滑块范围设置
    ui->slider1->setRange(10, 50);
    ui->slider2->setRange(10, 50);

    gpioSleep(0, 0, 2000);
}

void MainWindow::updateData(float x, float y, float z, int correct)
{
    // 主线程中处理数据,可安全操作UI
    qDebug() << "Received data:" << x << y << z << correct;
}

备选方案:修正继承QThread的写法

若坚持使用继承QThread的方式,需重写run方法并启动线程事件循环:

1. 修改Worker头文件

#include <QThread>
#include <QTimer>

class MyThreadWorker : public QThread
{
    Q_OBJECT

public:
    float x;
    float y;
    float z;
    int correct;

    MyThreadWorker();

private:
    Adafruit_BNO055 * imu_first;
    QTimer * timer;

protected:
    void run() override; // 重写run方法,替代自定义start

signals:
    void dataReady(float x, float y, float z, int correct);

private slots:
    void doWork();
};

2. 修改Worker源文件

#include "MyThreadWorker.h"

MyThreadWorker::MyThreadWorker() : QThread()
{
}

void MyThreadWorker::run()
{
    imu_first = new Adafruit_BNO055;
    imu_first->imu_initialization();

    timer = new QTimer();
    connect(timer, &QTimer::timeout, this, &MyThreadWorker::doWork);
    timer->start(1000);
    qDebug() << "start work in thread";

    exec(); // 启动线程事件循环,否则QTimer无法工作

    // 清理资源
    timer->stop();
    delete timer;
    delete imu_first;
}

void MyThreadWorker::doWork()
{
    imu_first->sig_bno_handler();
    gpioSleep(0, 0, 1000);
    imu_first->savevector();
    
    x = imu_first->myStruct.x;
    y = imu_first->myStruct.y;
    z = imu_first->myStruct.z;
    correct = imu_first->init_correct;
    qDebug() << "Dane: " << x;

    emit dataReady(x, y, z, correct);
}

3. 修改主窗口源文件

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    MyThreadWorker* worker = new MyThreadWorker();
    connect(worker, &MyThreadWorker::dataReady, this, &MainWindow::updateData);
    // 线程结束时自动清理
    connect(worker, &MyThreadWorker::finished, worker, &QObject::deleteLater);

    // 启动线程(调用QThread原生start方法,触发run)
    worker->start();

    // 滑块范围设置
    ui->slider1->setRange(10, 50);
    ui->slider2->setRange(10, 50);

    gpioSleep(0, 0, 2000);
}

void MainWindow::updateData(float x, float y, float z, int correct)
{
    // 处理数据
    qDebug() << "Received data:" << x << y << z << correct;
}

关键注意事项

  • 所有UI操作必须放在主线程的槽函数中(如updateData),Qt禁止子线程直接操作UI。
  • 跨线程信号槽连接默认使用Qt::QueuedConnection,可安全传递数据。
  • 通过finished信号连接deleteLater,避免内存泄漏。

内容的提问来源于stack exchange,提问作者hubertkulak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:23:19