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

QT中多线程启动后旧线程重复执行致数据混乱问题求助

问题:QThread重复执行与数据混乱

创建并启动Thread 1后,再创建启动Thread 2,发现Thread 1会再次运行,同时出现数据混乱。以下是代码及运行日志:

Worker.cpp代码

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void request_server(const QString& str_url, const qint64 &key_tag); {
        qint64 key_tag;
        qDebug() << "Worker ::request_server: " << QThread::currentThread() << ",id thread: " <<  QThread::currentThreadId() << ",key_tag: " << key_tag;
        /* ... 这里是耗时或阻塞操作 ... */
        emit resultReady(result, QThread::currentThread());
    }

signals:
    void resultReady(qint64 result, QThread *thread_req);
};

Controller.cpp代码

class Controller : public QObject
{
    Q_OBJECT
    
public:
    Controller() {
        
    }

    void request() {
        qint64 tag_req = QDateTime::currentMSecsSinceEpoch();
        QString str_url = "http:abc.xyz";

        Worker *worker = new Worker();
        QThread *workerThread = new QThread();
        worker->moveToThread(&workerThread);
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        connect(&workerThread, &QThread::finished, workerThread, &QObject::deleteLater);
        connect(this, &Controller::operate, worker, &Worker::request_server);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
        workerThread.start();
        
        emit operate(str_url, tag_req);
        qDebug()<<"Controller::request"<<tag_req;
    }

public slots:
    void handleResults(const qint64& tag, QThread* thread_req) {
         qDebug() << "Controller::updateResults" << tag << thread_req->currentThread() << thread_req->currentThreadId();

    }
signals:
    void operate(const QString &url, const qint64 &key_tag);
};

运行日志

Controller ::request  1709110337385
Controller ::request  1709110337401
Controller ::request  1709110337417
 Worker ::request_server:  QThread(0x2ad3c28e670) ,id thread:  0x27dc ,key_tag:  1709110337385
 Worker ::request_server:  QThread(0x2ad3c28e670) ,id thread:  0x27dc ,key_tag:  1709110337401
 Worker ::request_server:  QThread(0x2ad3c28e670) ,id thread:  0x27dc ,key_tag:  1709110337417
 Worker ::request_server:  QThread(0x2ad3c28e910) ,id thread:  0x118c ,key_tag:  1709110337401
 Worker ::request_server:  QThread(0x2ad3c28e910) ,id thread:  0x118c ,key_tag:  1709110337417
 Worker ::request_server:  QThread(0x2ad42ee7a10) ,id thread:  0x40b8 ,key_tag:  1709110337417
Controller ::updateResults 16044279834542133 QThread(0x2ad2a190050) 0x4114
thread_req is finished
Controller ::updateResults 16044279834542133 QThread(0x2ad2a190050) 0x4114
thread_req is finished
Controller ::updateResults 257 QThread(0x2ad2a190050) 0x4114
thread_req is finished
Controller ::updateResults 216 QThread(0x2ad2a190050) 0x4114
thread_req is finished
Controller ::updateResults 216 QThread(0x2ad2a190050) 0x4114
thread_req is finished
Controller ::updateResults 216 QThread(0x2ad2a190050) 0x4114
thread_req is finished

问题原因分析

  1. 槽函数变量重定义:request_server槽内重新定义了key_tag局部变量,覆盖了传入的参数,导致打印的是未初始化的栈内存值,直接引发数据混乱。
  2. moveToThread参数错误:worker->moveToThread(&workerThread)中,workerThread是指针类型,却传入了指针的地址,导致Worker被错误地关联到无效的线程对象,引发线程管理混乱。
  3. 信号重复连接:每次调用request()都会新增Controller::operate到Worker槽的连接,后续emit该信号时,所有已存在的Worker槽都会被触发,这就是旧线程重复运行的核心原因。
  4. 未初始化变量发送:resultReady信号发送的result未定义,导致日志中出现随机异常数值。

解决办法

1. 修复槽函数变量问题

删除request_server内的局部key_tag定义,直接使用参数值:

void request_server(const QString& str_url, const qint64 &key_tag) {
    // 移除 qint64 key_tag;
    qDebug() << "Worker ::request_server: " << QThread::currentThread() << ",id thread: " <<  QThread::currentThreadId() << ",key_tag: " << key_tag;
    /* ... 耗时操作 ... */
    qint64 result = 0; // 根据实际逻辑初始化并赋值result
    emit resultReady(result, QThread::currentThread());
}

2. 修正moveToThread参数

将错误的指针地址传入改为指针本身:

worker->moveToThread(workerThread);

3. 避免信号重复连接

使用Qt::UniqueConnection确保同一信号-槽对只连接一次:

connect(this, &Controller::operate, worker, &Worker::request_server, Qt::UniqueConnection);

4. 初始化发送变量

确保result有合法的初始化和赋值,避免发送未定义数据。

5. 优化线程管理(可选)

如果是周期性请求,推荐使用QThreadPool复用线程,避免频繁创建销毁线程的开销:

class WorkerRunnable : public QRunnable {
public:
    WorkerRunnable(const QString& url, qint64 tag, QObject* receiver) 
        : m_url(url), m_tag(tag), m_receiver(receiver) {}
    
    void run() override {
        qDebug() << "WorkerRunnable::run: " << QThread::currentThreadId() << ", key_tag: " << m_tag;
        /* 耗时操作 */
        qint64 result = 0;
        QMetaObject::invokeMethod(m_receiver, "handleResults", 
            Qt::QueuedConnection, Q_ARG(qint64, result), Q_ARG(qint64, m_tag));
    }

private:
    QString m_url;
    qint64 m_tag;
    QObject* m_receiver;
};

// Controller的request方法修改为:
void request() {
    qint64 tag_req = QDateTime::currentMSecsSinceEpoch();
    QString str_url = "http:abc.xyz";
    WorkerRunnable* runnable = new WorkerRunnable(str_url, tag_req, this);
    runnable->setAutoDelete(true);
    QThreadPool::globalInstance()->start(runnable);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:27:09