今天在进行串口调试时遇到一个报错:
QObject: Cannot create children for a parent that is in a different thread.

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0x5592cc80b0), parent's thread is QThread(0x5592cc7a40), current thread is QThread(0x7f88005b30)

捣鼓了小半天大致上弄清楚的报错的原因,在此记录一下。

先大概说一下代码情况:模块A通过串口基于modbus协议来控制机械臂的运动。既然用到了串口,在Qt中就需要使用QSerialPort类。而且上位机下发指令后需要不断回读状态以此判断对机械臂的操作是否成功,这是一个耗时操作,不能放在主线程中执行(否则会导致界面冻结),所以通过Qt的moveToThread将模块A移到线程中处理。

大概流程就是,模块A移到子线程,通过模块A的接口,调用到QSerialPort的write方法,将modbus指令发送到串口。因为模块A需要用到QSerialPort类,所以把QSerialPort对象声明为模块A的成员。

当调用到

serial->write(...);

时,就发生了上面的报错。

在gpt上先搜了一下QObject: Cannot create children for a parent that is in a different thread.这个报错的原因,给出的解释是在Qt中不能“跨线程创建 QObject 子对象

如何理解跨线程创建 QObject 子对象?简单来说就是假如类A属于主线程,类B属于子线程,那么在创建类B时就不能以类A为父类(这里类A和类B都继承自QObject)

写一段代码来验证一下

有三个类A、B、C,其中A通过moveToThread放在子线程(模拟项目中的模块A),B作为A的成员(模拟项目中的QSerialPort类)。然后在A中写一个funcA()函数,用来new一个类C,并且类C的父类传入B(模拟在子线程创建QObject 子对象)

//a.h
#ifndef A_H
#define A_H

#include <QObject>
#include "b.h"
#include "c.h"

class A : public QObject
{
    Q_OBJECT
public:
    explicit A(QObject *parent = nullptr);
    void funcA();
    
private: 
    B* b;   //类B作为A的成员对象(类B模拟QSerialPort类)
};

#endif // A_H
//a.cpp
#include "a.h"

A::A(QObject *parent) : QObject(parent)
{
    b = new B();
}

void A::funcA()
{
    C* c = new C(b);   //子线程中调用funcA方法,创建C对象,并以b作为父类
}
//main.cpp
#include <QCoreApplication>
#include <QThread>
#include "a.h"


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QThread* myThread = new QThread();

    A* mA = new A();
    mA->moveToThread(myThread);  //将类A移到子线程
    QObject::connect(myThread,&QThread::started,mA,&A::funcA);  
    //myThread开始时通过信号槽触发funcA函数,此时funcA会在子线程执行
    myThread->start();

    return a.exec();
}

运行结果:果然复现了QObject: Cannot create children for a parent that is in a different thread.这个报错

回到项目中,为什么调用serial->write(...)时会报这个错误呢?

首先,QSerialPort类是作为模块A的成员对象的,A是先在主线程中创建,此时无论是A还是A的成员QSerialPort,都属于主线程。然后通过moveToThread将A移到子线程中,通过调用A的接口再调用serial->write(...),此时serial->write(...)是在子线程中执行。serial->write(...)的内部执行了某种创建QObject子对象的操作,所以导致报错。

解决方法:想办法让模块A在子线程中创建,而不是主线程。

A::A(QObject *parent) : QObject(parent)
{
    QThread* myThread = new QThread();
    this->moveToThread(myThread);
}

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐