QThreadPool使用报错求助:跨线程事件发送断言失败问题
问题:QThreadPool替代QThread时出现跨线程事件发送错误
代码示例
MyTask.cpp
class MyTask : public QObject, public QRunnable { Q_OBJECT public: explicit MyTask(QObject* parent = nullptr) : QObject(parent) {} void run() override { qDebug() << "create new thread"; } signals: };
Controller.cpp
class Controller : public QObject { Q_OBJECT public: Controller(QObject* parent = nullptr) : QObject(parent) {} public slots: void request() { // 在主线程或GUI管理线程中创建MyTask MyTask* task = new MyTask(this); // 将MyTask放入QThreadPool执行 QThreadPool::globalInstance()->start(task); } };
main.cpp
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Controller* m_controller = new Controller(); QTimer timer; timer.setInterval(1000 / FPS); QObject::connect(&timer, &QTimer::timeout, m_controller, &Controller::request); timer.start(); return a.exec(); }
运行错误
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x26cfee9ebc0. Receiver '' (of type 'Controller') was created in thread 0x0x26ce78368b0"
原因分析
核心问题是跨线程的QObject父子关系冲突:
- MyTask同时继承
QObject和QRunnable,创建时将主线程中的Controller作为父对象。 - 当QThreadPool把MyTask分配到子线程执行后,MyTask作为QObject的生命周期管理会依赖父对象,但Qt禁止向不同线程的QObject发送事件(比如销毁事件),子线程中的MyTask尝试与主线程的父对象通信时触发断言错误。
解决方案
方案1:移除MyTask的父对象(推荐)
QThreadPool默认会自动删除执行完成的QRunnable(autoDelete()默认返回true),不需要通过父对象管理内存,修改request()函数即可:
void request() { MyTask* task = new MyTask(); // 去掉父对象参数 QThreadPool::globalInstance()->start(task); }
方案2:保留父对象并调整线程亲和性(不推荐)
如果必须保留父子关系,需将MyTask的线程亲和性切换到主线程,但这会让MyTask的run()函数在主线程执行,完全失去线程池的多线程优化意义,因此不推荐该方式。
信号槽的影响说明
当前问题与信号槽无关,但如果后续给MyTask添加信号连接到Controller的槽:
- 默认的
Qt::AutoConnection会自动判断线程,子线程发信号时会自动转为Qt::QueuedConnection,可安全实现跨线程通信,不会触发错误。 - 错误的根源始终是跨线程的QObject父子关系,而非信号槽机制本身。
内容的提问来源于stack exchange,提问作者KaiAkiho
相关产品推荐
相关产品推荐

