Qt:QObject。无法为位于不同线程中的父级创建子级

时间:2016-10-24 03:58:17

标签: c++ multithreading qt asynchronous signals-slots

我遇到了问题,我正在尝试将某些QThread与主GUI同步,但效果不佳!

我有一个主窗口(我有一些窗口,但问题似乎是相同的),它将与两种设备交互:一个串口(使用qserialport)和一个摄像头(使用opencv)。

为了使它们工作,我需要使用并行处理。我做了三个QThreads: *一个用于在设备和主窗口之间进行同步(主要用于复杂操作) *一个管理串口(使用libqt5serialport) *一个用于管理视觉算法。

为了在这些过程之间进行通信,首先,我正在尝试使用信号和插槽(也许,我可能会使用共享内存,互斥或它们的组合)。

当我尝试将来自我的串行端口对象的信号连接到QThread中的插槽时,未调用插槽并且我收到警告(执行时间): QObject:无法为位于其他线程中的父级创建子级。

代码非常简单,Vision的代码没有在这段代码中实现,我需要确定我可以沟通的过程可能是非常概念性的,当我试图站立时,我不能。

action.cpp:

#include "action.h"

Action::Action(QObject *parent, estadoGeneral *Estado)
    : QThread(parent)
{
    myEstado = Estado;

//Create new QThreads, one for camera aon other for serial port
    tCommunication = new ActionCommunication(this, myEstado);
    tVision = new ActionVision(this, myEstado);

}

Action::~Action()
{
    //TODO: free memory, stop, etc.
}

void Action::run()
{

    cout << "run() Action, id: " << QThread::currentThreadId() << endl;

    Action me;
    QTimer myTimer;

    //Esto si funciona
//    connect(myEstado->myCommunication, &SerialCommunication::readyRead, &myAction, &Action::readData);

#ifdef _ALIVE
//Signal works
    connect(&myTimer, &QTimer::timeout, &me, &Action::estaVivo);
    myTimer.start(10000);
#endif

    tCommunication->start();
//tVision->start();
    exec();
}

//Signal to connect
void Action::conectarSerie()
{
    cout << "Petición de conectar enviada por id " << QThread::currentThreadId() << endl;
    emyt sConectar();
}

void Action::enviarComando(int Comando)
{
    cout << "Petición de comando " << QThread::currentThreadId() << endl;
    emyt sEnviarComando1(Comando);
}
void Action::enviarComando(int Comando, int arg1)
{
    cout << "Petición de comando " << QThread::currentThreadId() << endl;
    emyt sEnviarComando2(Comando, arg1);
}

//Just a test
void Action::estaVivo()
{
    cout << "Action está vivo, signal id: " << this->currentThreadId() << endl;
}

//QThread to manage serial port
ActionCommunication::ActionCommunication(QObject *parent, estadoGeneral *Estado)
    : QThread(parent)
{
    mainParent = parent;
    myEstado = Estado;
}

ActionCommunication::~ActionCommunication()
{
//TODO
}

void ActionCommunication::run()
{
    cout << "run() ActionCommunication, id: " << QThread::currentThreadId() << endl;

    myEstado->myCommunication = new SerialCommunication();
    ActionCommunication me;

    me.myEstado = myEstado;
    //Connect the signals
    {
        connect(mainParent, SIGNAL(sConectar()), &me, SLOT(conectar()));
        connect(mainParent, SIGNAL(sEnviarComando1(int)), &me, SLOT(EnviarComando1(int)));
        connect(mainParent, SIGNAL(sEnviarComando2(int, int)), &me, SLOT(EnviarComando2(int, int)));

//Here is the problem
//*******************
        connect(myEstado->myCommunication, SIGNAL(readyStatus(int,int,int,int,int)),\
                &me, SLOT(readyStatus(int,int,int,int,int)));
    }
    exec();
}

//Try to communicate, it works
void ActionCommunication::conectar()
{
    cout << "connect - ActionCommunication id " << QThread::currentThreadId();
    myEstado->myCommunication->configurePort(myEstado->mysSettings);

    if(myEstado->myCommunication->openSerialPort()) emyt sConectado(true);
    else emyt sConectado(false);
}

//Send commands to serial port, it works
void ActionCommunication::EnviarComando1(int comando)
{

    cout << "Comando en ActionCommunication id " << QThread::currentThreadId();
//nComando is an enum, I cast in order to send via signal
    myEstado->myCommunication->enviarComando((nComando) comando);
}

void ActionCommunication::EnviarComando2(int comando, int arg1)
{

    cout << "Comando en ActionCommunication id " << QThread::currentThreadId();
    myEstado->myCommunication->enviarComando((nComando) comando,(nComando) arg1);
}
//Here is the problem, i never receive the signal sent by serialport, that is a `qserialport`
// ****************************************************************************************
// When the signal is received, I got the warning
void ActionCommunication::readyStatus(int id, int x, int y, int z, int t)
{
    cout << "Id: " << id << "x" << x << "..." << endl;
}

/******************
//Not implemented, interface to operate with opencv classes.
******************/
ActionVision::ActionVision(QObject *parent, estadoGeneral *Estado)
    : QThread(parent)
{

}

ActionVision::~ActionVision()
{

}

void ActionVision::run()
{

}

action.h:

#ifndef ACCION_H
#define ACCION_H

#include <QWidget>
#include <QObject>
#include <QThread>

#include "helpers.h"
#include "estadogeneral.h"
#include "vision.h"
//Here is the code that emit the signal, inherits QSerialPort
#include "comunicacionserie.h"

QT_BEGIN_NAMESPACE
class QImage;
QT_END_NAMESPACE

class ActionCommunication : public QThread
{
    Q_OBJECT

public:
    ActionCommunication(QObject *parent = 0, estadoGeneral *Estado=NULL);
    estadoGeneral *myEstado;
    ~ActionCommunication();

    QObject *mainParent;

    CommunicationSerie *myCommunication;

public slots:
    void conectar();
    void EnviarComando1(int comando);
    void EnviarComando2(int comando, int arg1);
// ********************* Problematic slot *******************
    void readyStatus(int id, int x, int y, int z, int t);

signals:
    void sConectado(bool);

protected:
    void run() Q_DECL_OVERRIDE;

private:

};

class ActionVision : public QThread
{
    Q_OBJECT

public:
    ActionVision(QObject *parent = 0, estadoGeneral *Estado=NULL);
    ~ActionVision();

protected:
    void run() Q_DECL_OVERRIDE;

private:

    estadoGeneral *myEstado;

};


class Action : public QThread
{
    Q_OBJECT

public:
    Action(QObject *parent = 0, estadoGeneral *Estado=NULL);
    ~Action();

    int irAFiducial(int nFiducial, bool esGlobal);
    void estaVivo();

    ActionCommunication *tCommunication;
    ActionVision *tVision;

    void conectarSerie();
    void enviarComando(int Comando);
    void enviarComando(int Comando, int arg1);
signals:
    void sConectar();
    void sEnviarComando1(int);
    void sEnviarComando2(int, int);
protected:
    void run() Q_DECL_OVERRIDE;

private:

    estadoGeneral *myEstado;
};


#endif // ACCION_H

PS: 另一个测试:我可以使用此readyRead连接到QThread(在我的方法中发出的信号,此信号对我没有QThreads有效),但不是我在CommunicationSerial中的信号,它有一个名为serial的对象并输入QSerialPort. connect(miEstado->miCommunication->serial, SIGNAL(readyRead()),\ &me, SLOT(datosPorLeer())); //参见注释5

返回ID(QThread::CurrentThreadId()

主进程ID:0x7f9ae9b2eac0(主窗口,QObject)

Action Id的方法run():0x7f9ac382b700(QThread)

ActionCommunication Id的方法run():0x7f9ac302a700(另一个QThread)

我的基于QSerialPort的对象(CommunicationSerial)中的Id:0x7f9ac302a700,打印在CommunicationSerial构造函数

插槽ID IdCommunication :: Conectar():0x7f9ac302a700(与程序失败的情况相同)

注1:我已翻译了部分代码,以便更容易理解。对不起,如果我犯了一个错误,我认为问题非常明确,我无法理解发生了什么。 QSerialPort的运行ID与ActionCommunication相同,我无法理解警告。

注意2:当我从串行端口(CommunicationSerial)接收信息时出现问题,我连接没有问题,当设备发送一些信息时,插槽readyData不会被执行。如果我在没有QThread的情况下使用此代码(直接来自主窗口代码),我没有问题。

注意3:当我收到数据时,会出现警告(QObject:无法为不同线程中的父项创建子项),我也会收到第二条消息: (Parent是QSerialPort(0x7f6ac4002c80),父线程是AccionComunicacion(0x1dbe810),当前线程是QThread(0x1d4be30) 请注意,它们是指针,可能它们从上次发生了变化。

另外,如果我尝试在CommunicationSerial->moveToThread(&me)的{​​{1}}方法中使用CommunicationSerial->moveToThread(this)run(),则警告是相同的。

注4:另外,我已经尝试过CommunicationSerial继承QObject(它继承了QSerialPort)并在CommunicationSerial中添加了一个QSerialPort对象,并添加了我需要的方法。结果是一样的。

注意5:我在CommunicationSerial-&gt; serial中添加了ActionCommunication的连接,即readyRead()对象的连接,并且它正常工作,但我继续遇到同样的问题来连接{在QSerialPort(我自己的信号)中{1}}收到上述错误。

**我继续发送数据,但我无法收到readyStatus信号。 (Parent是QSerialPort(0x7f6ac4002c80),父线程是AccionComunicacion(0x1dbe810),当前线程是QThread(0x1d4be30) 请注意,它们是指针,可能它们从上次发生了变化。

0 个答案:

没有答案