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

Qt报错:QObject无法为不同线程的父对象创建子对象

Qt跨线程创建QObject子对象报错解决

报错信息

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QUdpSocket(0x557d126bb830), parent's thread is QThread(0x557d11d1d680), current thread is QThread(0x557d126c64d0)

开发环境

  • 编译器:GCC 13.2.1
  • Qt版本:5.15.11
  • Qt Creator版本:11.0.3

最小复现代码

main.cpp

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QMainWindow w;
    w.show();

    UDPClient c(&w, QHostAddress("192.168.1.255"), 5001);
    MyProcessing p(NULL, "Hi!");

    QTimer timer;
    timer.setInterval(1000);
    timer.setTimerType(Qt::TimerType::PreciseTimer);

    QObject::connect(&timer, SIGNAL(timeout()), &p, SLOT(onTimeout()));
    QObject::connect(&p, SIGNAL(sigNewDataReady(QByteArray)),
                     &c, SLOT(onNewUDPDataReceived(QByteArray)),
                     Qt::DirectConnection);

    p.start();
    timer.start();

    return a.exec();
}

udpclient.h

#ifndef UDPCLIENT_H
#define UDPCLIENT_H

#include <QObject>
#include <QThread>
#include <QUdpSocket>

class UDPClient : public QObject
{
    Q_OBJECT
public:
    explicit UDPClient(QObject *parent = nullptr,
                       QHostAddress aAddr = QHostAddress("192.168.0.20"),
                       quint16 aPortNum = 0);
public slots:
    void onNewUDPDataReceived(QByteArray data);

private:
    QUdpSocket  *udpSocket;
    quint16      portNum;
    QHostAddress addr;
};

#endif // UDPCLIENT_H

udpclient.cpp

#include "udpclient.h"

UDPClient::UDPClient(QObject *parent, QHostAddress aAddr, quint16 aPortNum)
    : QObject{parent}
{
    portNum = aPortNum;
    addr    = aAddr;
    udpSocket = new QUdpSocket();
}

void UDPClient::onNewUDPDataReceived(QByteArray data)
{
    udpSocket->writeDatagram(data, addr, portNum);
} 

myprocessing.h

#ifndef MYPROCESSING_H
#define MYPROCESSING_H

#include <QObject>
#include <QThread>

class MyProcessing : public QObject {
    Q_OBJECT
public:
    MyProcessing(QObject *parent = nullptr, QByteArray text = "text");

    void start() { mThread->start(); }

signals:
    void sigNewDataReady(QByteArray);

public slots:
    void onTimeout() {emit sigNewDataReady(QByteArray(mText)); }

private:
    QByteArray mText;
    QThread *mThread;
};

#endif // MYPROCESSING_H

myprocessing.cpp

#include "myprocessing.h"

MyProcessing::MyProcessing(QObject *parent, QByteArray text)
    : QObject{parent}
{
    mText = text;
    mThread = new QThread;
    this->moveToThread(mThread);
}

问题原因

报错核心是跨线程调用了属于主线程的QUdpSocket方法:

  1. MyProcessing对象被移到自身子线程运行
  2. 信号sigNewDataReady与槽onNewUDPDataReceived使用Qt::DirectConnection,导致槽函数直接在信号发射的子线程中执行
  3. UDPClient和内部的udpSocket都属于主线程,子线程中调用udpSocket->writeDatagram时,QUdpSocket内部会创建临时子对象,其父对象是主线程的udpSocket,触发跨线程创建子对象的报错。

解决方案

方案1:修改信号槽连接类型

将Qt::DirectConnection改为默认的Qt::AutoConnection(可省略),Qt会自动判断线程,跨线程时自动用队列连接,让槽函数在UDPClient所属主线程执行:

QObject::connect(&p, SIGNAL(sigNewDataReady(QByteArray)),
                 &c, SLOT(onNewUDPDataReceived(QByteArray)));
// 或显式指定:
// QObject::connect(&p, SIGNAL(sigNewDataReady(QByteArray)),
//                  &c, SLOT(onNewUDPDataReceived(QByteArray)),
//                  Qt::AutoConnection);

方案2:确保QUdpSocket操作在所属线程执行

若必须使用直接连接,可在UDPClient中将writeDatagram操作通过队列投递到自身线程:
修改udpclient.cpp的onNewUDPDataReceived方法:

void UDPClient::onNewUDPDataReceived(QByteArray data)
{
    if (QThread::currentThread() != this->thread()) {
        QMetaObject::invokeMethod(this, "onNewUDPDataReceived",
                                  Qt::QueuedConnection,
                                  Q_ARG(QByteArray, data));
        return;
    }
    udpSocket->writeDatagram(data, addr, portNum);
}

方案3:将UDPClient移到子线程(可选)

若业务需要,可将UDPClient整体移到子线程,注意所有操作需通过信号槽或队列调用保证线程安全:

// 在main.cpp中添加
QThread* clientThread = new QThread;
c.moveToThread(clientThread);
clientThread->start();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 00:44:53