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
问题原因分析
- 槽函数变量重定义:
request_server槽内重新定义了key_tag局部变量,覆盖了传入的参数,导致打印的是未初始化的栈内存值,直接引发数据混乱。 - moveToThread参数错误:
worker->moveToThread(&workerThread)中,workerThread是指针类型,却传入了指针的地址,导致Worker被错误地关联到无效的线程对象,引发线程管理混乱。 - 信号重复连接:每次调用
request()都会新增Controller::operate到Worker槽的连接,后续emit该信号时,所有已存在的Worker槽都会被触发,这就是旧线程重复运行的核心原因。 - 未初始化变量发送:
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
相关产品推荐
相关产品推荐

