利用Qt多线程机制实现双路串口数据流的接收和发送

在上一篇文章的基础上,编写了一个对话框程序,可同时收发两路串口数据,每一路串口均在独立的子线程中实现。增加了清空edit的按钮。

1主程序界面

在这里插入图片描述

2两个子线程的线程号(调试信息中输出)

在这里插入图片描述
主线程的ID号为0x179c,两个串口子线程类的构造均是在主线程中,串口的启动、接收数据均在各自的子线程中,子线程ID号分别在0x14e4和0x5b0。而串口的关闭是在主线程中。这是和connect的配置有关。代码如下:

#include "serialcontroller.h"
#include <QDebug>

SerialController::SerialController(QObject *parent) : QObject(parent)
{
    
    
    m_portId = -1;
}

SerialController::~SerialController()
{
    
    
    if(m_serialThread.isRunning())
    {
    
    
        m_serialPort->closePort();
        delete m_serialPort;
        m_serialThread.quit();
        m_serialThread.wait();
     }

}
void SerialController::initCtrl(int portId,QString portName,long portBaud)
{
    
    
    m_portId = portId;
    m_portName = portName;
    m_portBaud = portBaud;
    qDebug()<<"Controller is running in main thread: "<<QThread::currentThreadId();

    //实例对象保存在堆上,没有父对象的指针要想正常销毁,需要将线程的 finished() 信号关联到 QObject 的 deleteLater() 让其在正确的时机被销毁

    m_serialPort = new SerialPort(m_portId,m_portName,m_portBaud);
    //m_serialPort对象不能有父对象。
    m_serialPort->moveToThread(&m_serialThread);

    connect(this,&SerialController::startRunning,m_serialPort,&SerialPort::startPort);
    connect(&m_serialThread,&QThread::finished,m_serialPort,&QObject::deleteLater);
    connect(this,&SerialController::ctrlSendData,m_serialPort,&SerialPort::write_Data);//从主线程发来的数据写入串口
    connect(m_serialPort,&SerialPort::receive_data,this,&SerialController::ctrlReceiveData);//从串口读取的数据发送给主线程
}
void SerialController::startCtrl()
{
    
    
    m_serialThread.start();
    emit startRunning();

}
void SerialController::stopCtrl()
{
    
    
    if(m_serialThread.isRunning())
    {
    
           
        m_serialPort->closePort();
        m_serialThread.quit();//会自动发送finished信号
        m_serialThread.wait();       
    }
}

串口的启动和接收数据所在的函数startPort与QThread类的connect信号关联,因此是在子线程中执行;而串口的关闭函数closePort没有与connect关联,不是槽函数,是在SerialController类的stopCtrl中执行,SerialController存在于主线中,因此closePort在主线程中执行。
因此,这里验证里上一篇文章中的重点(3):
(3)controller、worker 对象到底在哪个线程?「在哪创建就属于哪」这句话放在任何地方都是适用的。而 moveToThread() 函数的作用是将槽函数在指定的线程中被调用。也就是说controller、worker对象均在主线程中。除了绑定在connect上的槽函数(及槽函数体调用的函数)外,worker的其余函数也在主线程中执行。这个connect发送者可以是SerialController本身(this),也可以是m_serialThread
moveToThread()并不是将整个worker 对象“搬移”到controller线程中,而是将connect中的槽函数放到controller线程中执行。不注意这一点的话,很可能出现“QObject::Cannot create children for a parent that is in a different thread”问题。或者出现“耗时工作代码”仍在主线程中运行的情况。

猜你喜欢

转载自blog.csdn.net/SmartTiger_CSL/article/details/104383717
今日推荐