Qt多线程问题分析及解决思路QObject: Cannot create children for a parent that is in a different thread


Chapter1 Qt多线程问题分析及解决思路QObject: Cannot create children for a parent that is in a different thread

原文链接:https://blog.csdn.net/laoponline/article/details/118003801

一篇又臭又长的流水账,要看结论可以直接拉到最后。

在一个项目中,需要使用串口接收外部的对射管状态,然后调用传感器。由于在之前的项目中,自制了一个带有UI的串口管理类(继承QDialog)最早在主线程中生成这个串口管理类。但是发现程序变得越来越复杂以后,主线程会出现几十甚至几百毫秒的的连续占用,可能会导致串口响应不及时,状态刷新迟到,传感器采集不到完整的图像。

准备将带有UI的QSerialport通过Movetothread直接丢到子线程里运行,发现带有UI的类是不能这么干的…于是只能苦哈哈的重写这个串口管理类。

最早的想法是,将QSerialport直接Movetothread,发现可以编译通过,但是并没有卵用。仔细研究后发现,这个QSerialport是在串口管理类中直接声明的。由于串口管理类是在Mainwindow的初始化中new出来的,这个QSerialport自然也是在主线程中生成的。

class Serial_with_Dialog : public QDialog
{
    Q_OBJECT
 
public:
    explicit Serial_with_Dialog(QWidget *parent = nullptr, QString port_name  = "", QPushButton* button = nullptr);
    ~Serial_with_Dialog();
    
    QSerialPort serial_port;
 
....

于是改为只声明指针,在CPP中new一个QSerialPort。发现会提示QObject: Cannot create children for a parent that is in a different thread。此时程序虽然可以正常运行,但是对QSerialPort进行操作依旧是在主线程中进行。

头文件中:
class Serial_with_Dialog : public QDialog
{
    Q_OBJECT
 
public:
    explicit Serial_with_Dialog(QWidget *parent = nullptr, QString port_name  = "", QPushButton* button = nullptr);
    ~Serial_with_Dialog();
    
    QSerialPort* serial_port;
 
....
 
 
 
cpp文件中:
...
 
serial_port = new QSerialPort;
 
...

根据之前的研究经验,即使Movetothread后,如果直接调用函数,函数还是会在调用者的线程中运行。必须通过信号和槽进行QueuedConnection连接,才能通过槽让函数运行在子线程上。于是为QSerialport重新写了一个包含类Serial_Thread,继承了QObject,并将这个包含类movetothread。

头文件中:
 
class Serial_Thread : public QObject
{
    Q_OBJECT
 
public:
    explicit Serial_Thread(QWidget *parent = nullptr);
    ~Serial_Thread();
 
    QSerialPort* serial_port;
....
 
 
 
class Serial_with_Dialog : public QDialog
{
    Q_OBJECT
 
public:
    explicit Serial_with_Dialog(QWidget *parent = nullptr, QString port_name  = "", QPushButton* button = nullptr);
    ~Serial_with_Dialog();
 
 
    Serial_Thread* serial_thread;
 
 
 
CPP文件中:
 
Serial_with_Dialog::Serial_with_Dialog(QWidget *parent, QString port_name, QPushButton *button) :
    QDialog(parent) ,
    ui(new Ui::Serial_with_Dialog)
{
    ui->setupUi(this);
 
 
    //Language_Change(); //切换语言
    serial_thread = new Serial_Thread(nullptr);
serial_thread = new Serial_Thread(nullptr);
 
.....
 

这里在Serial_Thread中将QSerialPort* serial_port;暴露出来,主要是因为在Serial_with_Dialog中有许多直接调用QSerialPort进行串口开关、收发等操作的函数。为了减少对这些函数的修改,通过指针直接调用这个QSerialPort。经过一番修改,程序可以正常运行,但是在qdebug窗口中会出现错误提示:

QObject: Cannot create children for a parent that is in a different thread

字面意义是说,不能在一个线程中为不在同一个线程中的父类生成新的成员。由于程序可以正常运行,就没有在意。但是经过仔细的测试,发现虽然对这个QSerialPort进行读、写操作的函数,都在子线程中运行,但是实际上这个QSerialPort本身依旧是在主线程中进行处理的。通过while(1)卡死主线程后,这个QSerialPort就失去了响应。

经过网上一番搜索,也没有对应的方案。于是自己一点点思考,感觉可能是因为这个QSerialPort是在Serial_Thread的构造函数中生成的。因为构造函数是在主线程中运行的,这个QSerialPort必然也是在主线程中生成的,所以必然在主线程中处理。于是给Serial_Thread写了个Init函数,通过信号连接,等Serial_Thread所处的QThread运行start()以后再通过信号调用初始化。

void Serial_Thread::Init()
{
 
   qDebug()<<tr("[Serial_Thread]Init, time= %1, @ %2").arg(clock()).arg(QString::number(quintptr(QThread::currentThreadId())));
   serial_port = new QSerialPort(nullptr);   //新建
   QObject::connect(serial_port, &QSerialPort::readyRead, this, &Serial_Thread::Serial_Read,Qt::QueuedConnection); //连接读取函数
}

经过debug测试,这次Init确实是在子线程中运行了,但是QObject: Cannot create children for a parent that is in a different thread的提示依旧在,QSerialPort也依旧在主线程中运行。转了半天原来还在原地。

没有放弃,继续测试,在Serial_Thread中,其它的槽函数中另外new多个QSerialPort出来,发现只要不把这个QSerialPort的指针赋给serial_port,就不会出现前面的错误提示。甚至在Serial_Thread声明了一个无用的serial_port2,将new出来的QSerialPort赋值给它,也不会出现错误提示。

结合之前的实验仔细思考了一下,Serial_Thread是在主线程中生成的,属于Mainwindow。通过Movetothread到新线程中的QObject,自身应该是分裂(或者说复制)成了两分。原来的那一份还是在主线程,或者叫做父线程中运行,通过指针可以直接调用。在新线程中,生成了新的一份实体,其中跟父线程完全无关的部分成员,会在生成并且运行在子线程中,跟父线程有直接关联的部分,实际调用的还是在主线程中运行,一些成员变量则会保持同步。(纯猜想)

通过实验验证,在子线程中new一个QSerialPort,只要不将其指针赋值给serial_port,而是赋值给无用的serial_port2,就不会出现错误提示。一旦想要通过任何方式将其指针赋值给在串口管理类中会有调用的serial_port,还是会出现前的错误提示。QT应该是通过某种预处理上的的魔法操作,判定在Serial_Thread的所有者中,会直接调用serial_port,于是规定serial_port必须留在主线程。

看来是没得偷懒了,必须对程序结构进行大改动。删除原先串口管理类中所有对于QSerialPort的直接调用,全部改为通过信号和槽进行调用。改了一个小时,终于将serial_port变为了Serial_Thread的私有成员,所有操作都通过线程间的消息进行传递。

头文件中:
class Serial_Thread : public QObject
{
    Q_OBJECT
 
public:
    explicit Serial_Thread(QWidget *parent = nullptr);
    ~Serial_Thread();
 
    bool isOpen() { return m_isOpen;}
    int error() { return m_error;}
    QString errorString() { return m_error_string;}
 
 
    QSerialPort* port() {return serial_port;}
signals:
    void signal_direct_incoming(QByteArray index,long sendtime = 0);   //子线程直接发出的信号,不受主线程的影响
public slots:
    void Slot_Send(QByteArray index);  //发送字符串
    void Slot_Clear();   //清空缓冲区
 
    void Init();
    void Slot_PortOpen(QSerialPortInfo info, int baudrate);
    void Slot_PortClose();
    void Slot_CheckError();
private slots:
    void Serial_Read();
 
private:
    QSerialPort* serial_port;
.....
 
 
 
class Serial_with_Dialog : public QDialog
{
    Q_OBJECT
 
public:
    explicit Serial_with_Dialog(QWidget *parent = nullptr, QString port_name  = "", QPushButton* button = nullptr);
    ~Serial_with_Dialog();
 
 
    Serial_Thread* serial_thread;
.....
 
signals:
    void signal_Log_Add(QString index);
    void signal_incoming(QByteArray index);  //通过界面转发的数据。这里通过了一层转发,速度会受到主线程工作强度的影响
    
    void signal_Init();  //在子线程中初始化
    void signal_PortOpen(QSerialPortInfo info, int baudrate);  //对子线程中的实体QSerialport进行操作
    void signal_PortClose();
    void signal_CherkError();
    void signal_Clear();
    void signal_Send(QByteArray index);
 
......
 
 
 
CPP文件中:
 
Serial_with_Dialog::Serial_with_Dialog(QWidget *parent, QString port_name, QPushButton *button) :
    QDialog(parent) ,
    ui(new Ui::Serial_with_Dialog)
{
    ui->setupUi(this);
 
 
    //Language_Change(); //切换语言
    serial_thread = new Serial_Thread(nullptr);
    QThread *thread_serial = new QThread(nullptr);   //为保证实时性,移动到子线程中进行调用
    serial_thread->moveToThread(thread_serial);
    QObject::connect(thread_serial, &QThread::finished, this, &QObject::deleteLater);      // 清理线程
    thread_serial->start(); // 开启线程
 
    QObject::connect(this, &Serial_with_Dialog::signal_Init, serial_thread, &Serial_Thread::Init,Qt::BlockingQueuedConnection); //连接发送函数
    signal_Init();
 
    QObject::connect(serial_thread, &Serial_Thread::signal_direct_incoming, this, &Serial_with_Dialog::Serial_Read,Qt::QueuedConnection); //连接读取函数
    QObject::connect(this, &Serial_with_Dialog::signal_Send, serial_thread, &Serial_Thread::Slot_Send,Qt::QueuedConnection); //连接发送函数
    QObject::connect(this, &Serial_with_Dialog::signal_Clear, serial_thread, &Serial_Thread::Slot_Clear,Qt::QueuedConnection); //连接发送函数
 
    QObject::connect(this, &Serial_with_Dialog::signal_PortOpen, serial_thread, &Serial_Thread::Slot_PortOpen,Qt::BlockingQueuedConnection);   //对串口进行操作的函数,需要等待操作结束
    QObject::connect(this, &Serial_with_Dialog::signal_PortClose, serial_thread, &Serial_Thread::Slot_PortClose,Qt::BlockingQueuedConnection);
    QObject::connect(this, &Serial_with_Dialog::signal_CherkError, serial_thread, &Serial_Thread::Slot_CheckError,Qt::BlockingQueuedConnection);
......
 

最终完成测试已经是两个小时以后了…这次终于达成了目的,初始化中不在出现前面的错误提示,QSerialPort完全在子线程中运行,即使主线程进入while(1)卡死,QSerialPort依旧可以正常响应外部输入的串口消息,并且与处于其他子线程中的类进行交互。

结论:

1. QObject: Cannot create children for a parent that is in a different thread 这个错误提示的实际意思是,不能在子线程中生成跨线程调用的成员。如果一个成员在父线程中被直接调用了,那么这个成员必须处在父线程中,强行在子线程中生成就会出现这个错误提示。

2. 要一个成员完全处于子线程中进行处理,则只能通过信号与其进行交互。

3. QT的预处理是真的有魔法

<根本原因分析及重要解决方法>Chapter2 关于QObject: Cannot create children for a parent that is in a different thread

网上找了半天资料,都看得云里雾里,直到看到这篇文章:https://blog.csdn.net/MYTCHITOS/article/details/105892321

作为一个qt初学者,免不了要踏入QObject: Cannot create children for a parent that is in a different thread这个坑,不论是官方文档、stackoverflow还是csdn,看了半天也摸不着头脑,只好老老实实研究错误代码,最终解决了问题,这里记录一下。
代码从这里开始,一些不同重要的内容就略去了。

Class Worker:public QObject
{
	QTcpSocket tcpSocket;
public:
	Worker();
};

Class Controller:public QObject
{
public:
	Controller();
};

Controller::Controller()
{
	Worker worker=new Worker;
	QThread threads=new Qthreads;
	worker->moveToThread(threads);
	threads->start();
}

这个时候编译,其实也能通过,并且能够执行,但就是在执行的时候qt发出了

QObject: Cannot create children for a parent that is in a different thread
(Parent is QTcpSocket(0xdc3e80), parent's thread is QThread(0xcebf20), current thread is QThread(0xdc4160)

先不管这里什么意思,问题怎么解决呢?就是这样

Class Worker:public QObject
{
	QTcpSocket *tcpSocket;
public:
	Worker()
	{
		tcpSocket=new QTcpSocket(this);
	}
};

这里的关键是在new tcpSocket对象时传入的this参数,这个参数表示tcpSocket这个对象的父对象是这个Worker的一个实例。
我们回头看,为什么这样就可以了。
首先要明确一点,这个错误提示是qt本身对线程处理机制带来的,不是C++本身的问题,也与通常的线程机制无关。
我们可以看到在Controller的构造函数中创建了一个Worker对象worker,以及一个QThread对象threads,然后把这两个对象连接起来。那么问题就是,在Qt看来,调用Controller构造函数的线程,与threads代表的线程是两个线程,而在构造worker时所顺便创建的QTcpSocket对象tcpSocket与worker本身最初同属于Controller所在的线程,worker执行moveToThread之后,worker就转移到了threads所代表的线程中,但是,要注意,tcpSocket仍然属于Controller所在的线程,于是在调用threads->start()的时候就会出现错误提示。
而在构造tcpSocket时如果明确指明其父对象,那么在将worker与threads挂钩时,就会自动的也把tcpSocket与threads挂接起来,于是问题解决。当然,这一点是我猜的,但不管怎么说,执行结果可以证明一切。
显然,如果不使用moveToThread而是重载run来实现线程,其实也是免不了会掉进这个坑,道理上面说了,处理的思路也是一样的。

Chapter3 自己编写的多线程双串口例程

serialworker.h文件

#ifndef SERIALWORKER_H
#define SERIALWORKER_H

#include <QObject>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QByteArray>
#include <QThread>

struct serialParam {

};



class SerialWorker : public QObject
{
    Q_OBJECT
public:
    enum ErrorCodeFlag {
        NoErr = 0x0000,
        SerialPortOpenERR = 0x0001,
        ReadOnly = 0x0001,
        WriteOnly = 0x0002,
        ReadWrite = ReadOnly | WriteOnly
    };
    Q_DECLARE_FLAGS(ErrorCode, ErrorCodeFlag)

public:
    explicit SerialWorker(QObject *parent = nullptr);
    explicit SerialWorker(QString portName, qint32 baudrate);
    ~SerialWorker();

    QString ByteArrayToHexString(QByteArray data);


public slots:
    /*****************************************
     * 对应主线程的信号,需要的槽函数:
     *1. 打开串口槽函数
     *2. 关闭串口槽函数
     *3. 修改参数槽函数
     *****************************************/
    void slot_openPort(QString portName, qint32 baudrate);
    void slot_closePort();
    void slot_handleMessage();
    void slot_writeData(QByteArray data);

signals:
    /*****************************************
     *1. 通知主线程处理消息的信号
     *2. 同时该信号需要传递哪些参数
     *****************************************/
    void sig_handleResults(const QString &result);
    void sig_handleMsg(serialParam *para);
    //void sig_Error(qint32 errCode); //比如打开串口失败等
    void sig_Error(SerialWorker::ErrorCode); //比如打开串口失败等

private:
    QSerialPort *serialPort1; //串口通信对象
    serialParam *para1;
};

#endif // SERIALWORKER_H

serialworker.cpp文件

/*******************************************************************************
* 这里的关键是在new QSerialPort(this)对象时传入的this参数,这个参数表示serialPort1这个对象
* 的父对象时这个SerialWorker的一个实例。不加this就会导致QObject:Cannot create children for
* a parent that is in a different thread
******************************************************************************/
serialPort1 = new QSerialPort(this); //指定父对象为SerialWorker的一个实例

#include "serialworker.h"

SerialWorker::SerialWorker(QObject *parent) : QObject(parent)
{

}

SerialWorker::SerialWorker(QString portName, qint32 baudrate)
{
    /*******************************************************************************
     * 这里的关键是在new QSerialPort(this)对象时传入的this参数,这个参数表示serialPort1这个对象
     * 的父对象时这个SerialWorker的一个实例。不加this就会导致QObject:Cannot create children for
     * a parent that is in a different thread
     ******************************************************************************/
    serialPort1 = new QSerialPort(this); //指定父对象为SerialWorker的一个实例
    
    //设置端口名称和波特率
    serialPort1->setPortName(portName);
    serialPort1->setBaudRate(baudrate);


    //关联读取信号与槽函数:处理信息
    connect(serialPort1, &QSerialPort::readyRead, this, &SerialWorker::slot_handleMessage);

    qDebug()<<"SerialWorker::SerialWorker threadId:"<<QThread::currentThreadId();

}

SerialWorker::~SerialWorker()
{
    //申请的串口资源关闭,同时销毁,否则会导致内存泄漏
    if(serialPort1->isOpen())
    {
        serialPort1->close();
    }
    serialPort1->deleteLater();
}

QString SerialWorker::ByteArrayToHexString(QByteArray data)
{
    QString ret(data.toHex().toUpper());
    int len = ret.length()/2;
    qDebug()<<"收到字节长度为:"<<len;
    for(int i=1;i<len;i++)
    {
        ret.insert(2*i+i-1," ");
    }
    return ret;
}

void SerialWorker::slot_openPort(QString portName, qint32 baudrate)
{
qDebug()<<"SerialWorker::slot_openPort threadId:"<<QThread::currentThreadId();
if(serialPort1->open(QIODevice::ReadWrite))
{
qDebug()<<"SerialWorker::slot_openPort:open successfully...";
}
else
{
    qDebug()<<"SerialWorker::slot_openPort:open error ???";
    emit sig_Error(SerialWorker::ErrorCodeFlag::SerialPortOpenERR);
}
}

void SerialWorker::slot_closePort()
{
    if(serialPort1->isOpen())
    {
        serialPort1->close();
    }
}

void SerialWorker::slot_handleMessage()
{
    QByteArray buffer = serialPort1->readAll();
    // 2.进行数据处理
    QString result = ByteArrayToHexString(buffer);
    qDebug()<<"SerialWorker::slot_handleMessage threadId:"<<QThread::currentThreadId();
    qDebug()<<"子线程收到数据:"<<result;
    // 3.将结果发送到主线程
    emit sig_handleResults(result);
}

void SerialWorker::slot_writeData(QByteArray data)
{
    if(serialPort1->isOpen())
    {
        serialPort1->write(data);
    }
}

mainwindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "serialworker.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    QStringList findPort(void);

signals:
    void sig_OpenSerialport(QString portName, qint32 baudrate);
    void sig_serialWriteData(QByteArray data);

    void sig_OpenSerialport2(QString portName, qint32 baudrate);
    void sig_serialWriteData2(QByteArray data);

private slots:
    void on_pBtn_OpenSerialPort_clicked();
    void slot_errorCode(SerialWorker::ErrorCode);
    void slot_handleResults(const QString &result);

    void on_pBtn_SendData_clicked();

    void on_pBtn_OpenSerialPort_2_clicked();
    void slot_errorCode2(SerialWorker::ErrorCode);
    void slot_handleResults2(const QString &result);

private:
    Ui::MainWindow *ui;

    SerialWorker* serialWork1; //创建一个串口工作线程实例指针
    QThread threadSerial1; //串口工作线程

    SerialWorker* serialWork2; //创建一个串口工作线程实例指针
    QThread threadSerial2; //串口工作线程
};
#endif // MAINWINDOW_H

mainwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //搜寻添加串口
    QStringList list = findPort();
    ui->cmb_portName->addItems(list);
    ui->cmb_portName->setCurrentIndex(1);

    ui->cmb_portName_2->addItems(list);

    //波特率
    QStringList baudrateList;
    baudrateList<<"4800"<<"9600"<<"19200"<<"38400"<<"57600"<<"115200";
    ui->cmb_baudRate->addItems(baudrateList);//添加下拉列表选项
    ui->cmb_baudRate->setCurrentText("115200");//界面中初始值

    ui->cmb_baudRate_2->addItems(baudrateList);
    ui->cmb_baudRate_2->setCurrentText("115200");

    qDebug()<<"MainWindow::MainWindow threadId:"<<QThread::currentThreadId();

}

MainWindow::~MainWindow()
{
    delete ui;
    serialWork1->deleteLater();
    threadSerial1.quit();
    threadSerial1.deleteLater();

    serialWork2->deleteLater();
    threadSerial2.quit();
    threadSerial2.deleteLater();
}

QStringList MainWindow::findPort()
{
    QStringList list;
    //通过QSerialPortInfo查找可用串口
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        QString showName = info.portName();
        qDebug() << showName+":"+info.description();
        list.append(showName);
    }
    return list;
}


void MainWindow::on_pBtn_OpenSerialPort_clicked()
{

        serialWork1 = new SerialWorker(ui->cmb_portName->currentText().toLatin1().toStdString().data(), ui->cmb_baudRate->currentText().toInt());
        serialWork1->moveToThread(&threadSerial1);

        connect(serialWork1, &SerialWorker::sig_Error, this, &MainWindow::slot_errorCode);
        connect(&threadSerial1, &QThread::finished, serialWork1, &QObject::deleteLater);
        connect(serialWork1, &SerialWorker::sig_handleResults, this, &MainWindow::slot_handleResults); //从串口读取的数据发送给主线程
        connect(this, &MainWindow::sig_OpenSerialport, serialWork1, &SerialWorker::slot_openPort);
        connect(this, &MainWindow::sig_serialWriteData, serialWork1, &SerialWorker::slot_writeData); //从主线程发来的数据写入串口
        threadSerial1.start();
        emit sig_OpenSerialport(ui->cmb_portName->currentText(),ui->cmb_baudRate->currentText().toInt());

        ui->pBtn_OpenSerialPort->setEnabled(false);
}

void MainWindow::slot_errorCode(SerialWorker::ErrorCode code)
{
qDebug() << "MainWindow::slot_errorCode:"<< code;
}

void MainWindow::slot_handleResults(const QString &result)
{
    static quint32 cnt = 0;
    ui->textEdit->append(result);
    cnt++;
    ui->lineEdit_Cnt->setText(QString::number(cnt));

//    if(cnt > 50){
        cnt = 0;
//        ui->textEdit->clear();
//    }
}


void MainWindow::on_pBtn_SendData_clicked()
{
    QByteArray ba;
    ba.append(ui->lineEdit_Send->text());
    emit sig_serialWriteData(ba);
}


void MainWindow::on_pBtn_OpenSerialPort_2_clicked()
{
    serialWork2 = new SerialWorker(ui->cmb_portName_2->currentText().toLatin1().toStdString().data(), ui->cmb_baudRate_2->currentText().toInt());
    serialWork2->moveToThread(&threadSerial2);

    connect(serialWork2, &SerialWorker::sig_Error, this, &MainWindow::slot_errorCode2);
    connect(&threadSerial2, &QThread::finished, serialWork2, &QObject::deleteLater);
    connect(serialWork2, &SerialWorker::sig_handleResults, this, &MainWindow::slot_handleResults2); //从串口读取的数据发送给主线程
    connect(this, &MainWindow::sig_OpenSerialport, serialWork2, &SerialWorker::slot_openPort);
    connect(this, &MainWindow::sig_serialWriteData, serialWork2, &SerialWorker::slot_writeData); //从主线程发来的数据写入串口
    threadSerial2.start();
    emit sig_OpenSerialport(ui->cmb_portName_2->currentText(),ui->cmb_baudRate_2->currentText().toInt());

    ui->pBtn_OpenSerialPort_2->setEnabled(false);
}

void MainWindow::slot_errorCode2(SerialWorker::ErrorCode code)
{
qDebug() << "MainWindow::slot_errorCode2:"<< code;
}

void MainWindow::slot_handleResults2(const QString &result)
{
    static quint32 cnt = 0;
    ui->textEdit_2->append(result);
    cnt++;
//    if(cnt > 50){
        cnt = 0;
//        ui->textEdit_2->clear();
//    }
    ui->lineEdit_Cnt_2->setText(QString::number(cnt));
}

运行结果截图

在这里插入图片描述

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"QObject: Cannot create children for a parent that is in a different thread" 是一个错误消息,它表示在不同线程中无法为父对象创建子对象。这个错误通常发生在Qt框架的应用程序中,当你尝试在一个线程中创建一个子对象,并将它的父对象设置为另一个线程中的对象时。 这个错误的原因是Qt框架使用了线程安全的机制来确保对象的正确访问。每个对象都有一个与之相关联的线程,当你在一个线程中创建一个对象时,这个对象的父对象必须与它在同一个线程中。否则,就会出现上述错误。 为了解决这个问题,你可以考虑以下几种方法: 1. 确保在同一个线程中创建父对象和子对象。这意味着你需要在同一个线程中创建所有相关的对象。 2. 如果你确实需要在不同线程中创建对象,可以使用信号和槽机制将父对象和子对象进行连接。这样可以确保子对象的创建是在正确的线程中进行的。 3. 可能还有其他的解决方案,具体取决于你的应用程序的架构和需求。你可以查阅Qt框架的文档或者在Qt社区寻求帮助以获取更多的解决方案。 总之,"QObject: Cannot create children for a parent that is in a different thread" 错误通常是由在不同线程中创建父对象和子对象引起的。通过确保在相同的线程中创建相关对象,或者使用信号和槽机制进行连接,你可以解决这个错误。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [QObject: Cannot create children for a parent that is in a different thread错误](https://blog.csdn.net/lzjsqn/article/details/56287267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值