Qt多线程通信

【QT】:线程之间的通信操作(主线程与子线程,子线程与子线程和主线程同时通信,附源码案例) 多线程之间的变量传递 阅读详情
AI摘要

本文详细介绍了Qt中线程间通信的两种主要方式:共享内存和信号槽机制。重点讲解了如何使用信号槽机制在不同线程间传递数据,包括基本类型和自定义类型的数据传递方法。

简述:

1> Qt线程间共享数据主要有两种方式:

1)使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。

2)使用singal/slot机制,把数据从一个线程传递到另外一个线程。

第一种方法在各个编程语言都普遍使用,而第二种方法是QT的特有的,本文主要介绍第二种。

2 > 槽参数类型

1) 在线程间使用信号槽进行通信时,槽参数必须使用元数据类型的参数;

2) Qt内生的元数据类型,如int double QString等;

3) 如果要用自定义的数据类型,需要在connect之前将其注册(qRegisterMetaType)为元数据类型。

4) 线程间用“信号与槽”传递引用参数的话,要加const,因为const文字常量存在常量区中,生命周期与程序一样的长。这样可以避免slot调用的时候参数的运行期已过而使引用无效。

connect(m_thread, SIGNAL(MsgSignal(const QString&)),
              this, SLOT(OnMsgSignal(
const QString&)));

3 > Q_DECLARE_METATYPE与qRegisterMetaType 
Q_DECLARE_METATYPE

如果要使自定义类型或其他非QMetaType内置类型在QVaiant中使用,必须使用该宏。

该类型必须有公有的 构造、析构、复制构造函数。

qRegisterMetaType 

必须使用该函数的两种情况:

如果非QMetaType内置类型要在Qt的属性系统中使用。

如果非QMetaType内置类型要在queued 信号与槽中使用。

两者的关系:

Q_DECLARE_METATYPE展开后是一个特化后的类QMetaTypeId<TYPE>

qRegisterMetaType将某类型注册到MetaType系统中。

QMetaTypeId<TYPE>的类中成员包含对qRegisterMetaType的调用。

1、传递int参数(主线程与子线程)


testthread.h 文件

#ifndef TESTTHREAD_H  
#define TESTTHREAD_H  
  
#include <QThread>  
  
#include "msg.h"  
  
class TestThread : public QThread  
{  
    Q_OBJECT  
public:  
    explicit TestThread(QObject *parent = 0);  
  
protected:  
    void run();  
  
signals:  
    void TestSignal(int);  
  
private:  
    Msg msg;  
};  
  
#endif // TESTTHREAD_H 


testthread.cpp文件

#include "testthread.h"  
  
TestThread::TestThread(QObject *parent) :  
    QThread(parent)  
{  
}  
  
void TestThread::run()  
{  
    //触发信号  
    emit TestSignal(123);  
} 

自定义的类继承了QThread类,重写run函数,然后触发TestSignal信号。

mainwindow.h

#ifndef MAINWINDOW_H  
#define MAINWINDOW_H  
  
#include <QMainWindow>  
  
#include "testthread.h"  
  
namespace Ui {  
class MainWindow;  
}  
  
class MainWindow : public QMainWindow  
{  
    Q_OBJECT  
  
public:  
    explicit MainWindow(QWidget *parent = 0);  
    ~MainWindow();  
  
private slots:  
    void DisplayMsg(int);  
  
private:  
    Ui::MainWindow *ui;  
    TestThread *t;  
};  
  
#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);  
  
    //进行connect前必须实例化  
    t = new TestThread();     
  
    connect(t, SIGNAL(TestSignal(int)), this, SLOT(DisplayMsg(int)));  
  
    //执行子线程  
    t->start();   
}  
  
void MainWindow::DisplayMsg(int a)  
{  
    ui->textBrowser->append(QString::number(a));  
}  
  
MainWindow::~MainWindow()  
{  
    delete ui;  
} 

Mainwindow里面连接信号槽,并且将收到的int参数显示在界面上。
运行效果:



2、传递自定义参数(主线程与子线程)

对以上程序进行简单的修改,使它传递自定义消息。

testthread.h 文件

#ifndef TESTTHREAD_H  
#define TESTTHREAD_H  
  
#include <QThread>  
  
#include "msg.h"  
  
class TestThread : public QThread  
{  
    Q_OBJECT  
public:  
    explicit TestThread(QObject *parent = 0);  
    Msg msg;  
  
protected:  
    void run();  
  
signals:  
    void TestSignal(Msg);   //自定义消息Msg!!!  
};  
  
#endif // TESTTHREAD_H 

testthread.cpp文件

#include "testthread.h"  
  
TestThread::TestThread(QObject *parent) :  
    QThread(parent)  
{  
}  
  
void TestThread::run()  
{  
    msg.int_info = 999;  
    msg.str_info = "Hello Main Thread!";  
    //触发信号  
    emit TestSignal(msg);  
}  

mainwindow.h

#ifndef MAINWINDOW_H  
#define MAINWINDOW_H  
  
#include <QMainWindow>  
  
#include "testthread.h"  
#include "msg.h"  
  
namespace Ui {  
class MainWindow;  
}  
  
class MainWindow : public QMainWindow  
{  
    Q_OBJECT  
  
public:  
    explicit MainWindow(QWidget *parent = 0);  
    ~MainWindow();  
  
private slots:  
    void DisplayMsg(Msg);   //Msg!!!  
  
private:  
    Ui::MainWindow *ui;  
    TestThread *t;  
};  
  
#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);  
  
    //进行connect前必须实例化  
    t = new TestThread();  
  
    //Msg!!!  
    connect(t, SIGNAL(TestSignal(Msg)), this, SLOT(DisplayMsg(Msg)));  
  
    //执行子线程  
    t->start();  
}  
  
void MainWindow::DisplayMsg(Msg msg)  
{  
    ui->textBrowser->append(QString::number(msg.int_info));  
    ui->textBrowser->append(msg.str_info);  
}  
  
MainWindow::~MainWindow()  
{  
    delete ui;  
} 

此时再进行编译,编译通过,但Qt Creator会有提示:

QObject::connect: Cannot queue arguments of type 'Msg'  
(Make sure 'Msg' is registered using qRegisterMetaType().)

并且运行程序时会发现,信号发送了,槽函数始终不调用。

如果将槽参数注册为元数据类型,即mainwindow.cpp文件改动一下:

ui->setupUi(this);  
  
qRegisterMetaType<Msg>("Msg"); 

此时便可正常运行:



3、传递自定义参数(子线程与子线程)


原理同上,然后把connect函数中的第三参数this(主线程)改成要监听的另一个线程对象就好了(QT多么健壮、友好、强大)。

connect(t, SIGNAL(TestSignal(Msg)), this, SLOT(DisplayMsg(Msg)));  

前提是全部的线程都要在主线程里面实例化(new)。


4、传递自定义结构体参数(子线程与子线程)


实现子线程与GUI子线程的参数进行传递。

线程

头文件 ABFThread.h

public:  
  
    struct G_ABFTableSrcUnit  
    {  
        int a;  
        int b;  
        int c;  
        float d;  
        float e;  
        unsigned int f;  
        float Gg;  
      
        QString waveformTypel;  
    };  
  
public slots:  
  
    void parameterPassing(abfThread::G_ABFTableSrcUnit); //线程自己调用自己的结构体。。。必须这么写不然主线程会报错的  错误是参数内容不一样

ABFThread.cpp

void abfThread::parameterPassing(abfThread::G_ABFTableSrcUnit)  
{  
  
}  

GUI线程 

radarControl.h

#include "abfThread"  
  
private:  
    Ui::radarControl *ui;  
  
    abfThread::G_ABFTableSrcUnit mst_abfSrcUnit;  
  
  
signals:  
    void sendString(abfThread::G_ABFTableSrcUnit);
radarControl.cpp
按下按钮就发射信号

void radarControl::on_pushButton_clicked()  
{  
    emit sendString(mst_abfSrcUnit);  
}  
mainwindow.h
#include "abfThread.h"  
#include "radarControl.h"
mainwindow.cpp
radarInterface = new radarControl();  
m_ABFThread = new QThread();  
m_ABF = new abfThread();  
m_ABF->moveToThread(m_ABFThread);  
m_ABFThread->start();  
  
qRegisterMetaType<abfThread::G_ABFTableSrcUnit>("abfThread::G_ABFTableSrcUnit");  
connect(radarInterface,SIGNAL(sendString(abfThread::G_ABFTableSrcUnit)),m_ABF,SLOT(parameterPassing(abfThread::G_ABFTableSrcUnit)));  
//除了注册结构体外  还要保证传递的参数写法要一样  这就是为什么 前面线程自己定义的结构体自己调用自己的原因了 


小结:

1 > Qt的信号槽函数只默认支持Qt的类型和C++提供的内建的基本类型,比如int double float等,根本不支持C++的std::string std::vector 自定义的struct类型。所以需要用Qt提供的Q_DECLARE_METATYPE和qRegisterMetaType来声明和注册自定义的类型和C++的其他类型。
2 > 多线程间的信号槽传递,在connect的时候需要以Qt::QueuedConnection的方式,不然以Qt::DirectConnection的方式接收者UI线程会很长时间收不到后台线程发出的信号,或者信号直接丢失都是有可能的


Qt网络通信,多线程实现UDP通信 Qt使用多线程进行UDP通信 UDP 由于要使用套接字,所以需要在服务器和客户端的工程文件中都添加QT += core gui network 使用writeDatagram方法传输数据,readDatagram方法接收数据。QT在调用writeDatagram方法时候会自动发出readyRead信号给接收方监听。 多线程 Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里,即使用MoveToThread。    阅读详情

相关推荐

Qt 多线程之间的通信 实例 emit

Qt的信号与槽机制可以将任何继承自QObject类的对象捆绑在一起,使不同对象之间能够相互通信。

linux 1万+

Qt线程间数据通讯及数据共享

方法一:使用全局变量或全局函数, 使用全局变量或全局函数,在其他类或线程中调用,这是各种编程语言中都通用的方法,但全局变量长时间占用内存,影响程序空间使用率,且全局变量修改影响整个程序,程序的安全性无法保证,一般尽量少用全局变量或函数。 方法二:使用信号与槽 注意事项 只有QObject类及其派生的类才能使用信号和槽的机制 在线程间使用信号槽进行通信时,槽参数必须使用元数据类型的参数; 如果使用自定义的数据类型,需要在connect之前将其注册(qRegisterMetaType)为元数据类型; 线程间用

weixin_46338291的博客 2752

QT之串口通信和多线程处理

使用QT的多线程编程,完成串口通信助手的设计。

QtCompany的博客 1966

Qt线程/进程间通讯

Qt线程、进程间通信方法详解

weixin_42868530的博客 5332

QT 主线程子线程互相传值

QT多线程专栏共有14篇文章,从初识线程到、QMutex锁、QSemaphore信号量、Emit、Sgnals、Slot主线程子线程互相传值同步变量、QWaitCondition、事件循环、QObjects、线程安全、线程同步、线程异步、QThreadPool线程池等线程操作进行了全面!深入!的研究和详细的说明

断点 1万+

QT多线程与串口通信项目实战设计

Qt 是一个功能强大的跨平台 C++ 开发框架,广泛应用于 GUI 程序、嵌入式系统及高性能后端服务开发中。其核心模块包括 QtCore、QtGui 和 QtWidgets,其中 QtCore 提供了对多线程、文件操作、容器类等基础功能的封装,是构建高性能并发程序的基础。在现代软件开发中,多线程技术对于提升应用响应速度、实现后台任务处理至关重要,尤其在串口通信、数据采集、实时监控等场景中,Qt 提供了完整的线程通信机制,如信号与槽跨线程通信、QThread 管理、线程同步工具等。

weixin_29476595的博客 749

QT多线程通信

在主函数中,我们创建了两个线程,一个执行waitForData()函数,另一个执行sendData()函数,从而实现多线程的同步。总的来说,QFutureWatcher是一个功能强大的类,允许我们方便地监视和处理异步任务的结果。通过连接适当的信号和槽函数,我们可以灵活地处理异步操作的状态和结果,从而提高程序的响应性和性能。总的来说,QFuture是一个强大的类,提供了对异步操作结果的访问和监视功能。通过使用QFuture,你可以更好地管理异步操作的流程和状态,并避免阻塞主线程,从而提高程序的性能和响应性。

不知东方之既白 1795

Qt线程之间通信、线程和进程之间通信实例

Qt线程之间通信、线程和进程之间通信实例,简单易懂

Qt下实现多线程串口通信

Qt下实现多线程串口通信 Qt下无论是RS232、RS422、RS485的串口通信都可以使用统一的编码实现。本文把每路串口的通信各放在一个线程中,使用movetoThread的方式实现。 用SerialPort类实现串口功能,Widget类调用串口。 serialport.h如下: #include <QObject> #include <QSerialPort>...

《好好先生》专栏 4856

qt线程共享数据 信号和槽方式

使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的。 Qt 线程间共享数据是本文介绍的内容,多的不说,先来啃内容。Qt线程间共享数据主要有两种方式: 使用共享内存。即使用一个两个线程都能够共享的变量(如全局变量),这样两个线程都能够访问和修改该变量,从而达到共享数据的目的; 使用singal/slot机制,把数据从一个线程传递到另外一个线程。 第一种办法在各个编程语言都使用普遍,而第二种方式倒是QT的特有方式,下面主要学习一下这种方式

SAP CEWB 高效批量调整工艺路线与BOM的实战指南

本文详细介绍了SAP CEWB工具在批量调整工艺路线与BOM中的高效应用。通过实战案例和操作指南,帮助制造业企业快速掌握批量修改技巧,显著提升工作效率,避免手工操作带来的错误和耗时。特别适合需要频繁更新工艺路线和BOM的企业用户。

weixin_42524708的博客 398

基于Qt多线程实现UDP通信

基于Qt多线程实现UDP通信

hw5230的博客 3942

新入手的Atmel-ICE产品说明

【一句话自我介绍】 我是Atmel最新推出的功能强大的调试编程工具,适用于Atmel ARM® Cortex®-M的Atmel SAM和AVR® 系列芯片。 【我支持的软件】 完美支持Atmel Studio 6.2以上版本直接支持ICC8AVR以上版本支持烧录ICCAVR、CVAVR、IAR等生成的HEX文件 【我支持的器件】 支持AVR 32-bit MCUs的JTA

kaloha3的专栏 1万+

Qt|多线程串口通信

qt实现多线程串口通信

编程改变世界。想做一些改变世界的产品。感谢一键三连。 2814

别再乱选保护板了!手把手教你用ABLIC S-8254A为3/4串锂电池组DIY安全保护电路

本文详细介绍了如何使用ABLIC S-8254A保护集成电路为3/4串锂电池组DIY安全保护电路。从选型策略、电路搭建到功能验证,手把手教你实现可靠的充放电保护系统,适用于无人机、电动工具等场景,确保锂电池组的安全使用。

weixin_42525264的博客 189

INMP441麦克风避坑指南:为什么你的I2S录音总有杂音?(附示波器调试技巧)

本文针对INMP441麦克风与ESP32等MCU通过I2S接口连接时常见的录音杂音问题,提供了一套系统的硬件调试指南。文章深入剖析了电源纹波、信号完整性、接地环路及时钟抖动四大噪声根源,并详细讲解了如何使用示波器进行逐层排查,给出了增加LC滤波、串联阻尼电阻、优化布局布线等切实可行的解决方案,帮助开发者从根本上提升音频质量。

k0l1m2n3o的博客 1023

Qt QIODevice 多线程通信的一些问题

这时候就是Qt下这种串口通信的极致了,解决办法就是提高cpu 的性能,不要让cpu 浪费在其他无关的业务上。, 实际上 QObject::moveToThread: Cannot move objects with a parent 问题 和 Cannot create children for a parent that is in a different thread 警告是同一个问题,都是Qt为了保证 QObject 的父对象(parent)和它所在线程必须在同一个线程所设置的。可以验证前面的猜想。

刘子木 1075

EMC设计技巧及经验总结3:TVS的使用

Way back in undergrad circuits class(回到本科时的电路课程), our TA(助教) loved to give uslittle “black box” circuits. We’d measure the voltage and current characteristics, then have to determine what compone

snmplink的博客 2411

Qt下实现多线程的串口通信

简述 Qt下无论是RS232、RS422、RS485的串口通信都可以使用统一的编码实现。本文把每路串口的通信各放在一个线程中,使用movetoThread的方式实现。 代码之路 用SerialPort类实现串口功能,Widget类调用串口。 serialport.h如下 #include &amp;amp;amp;lt;QObject&amp;amp;amp;gt; #include &amp;amp;amp;lt;QSerialPort&amp;amp;amp;gt; #i

lusanshui的博客 2万+

【入门AUTOSAR网络管理测试】AUTOSAR网络管理规范需求解读

AUTOSARAutomotive Open System Architecture,汽车开放系统架构,由全球汽车制造商、部件供应商及其他电子、半导体和软件系统公司联合建立,致力于制定汽车电子软件标准的联盟。网络管理网络管理的目的是使网络中的ECU节点有序的睡眠和唤醒。在没有通信需求的时候睡眠,在需要通信的时候唤醒,可以节约汽车电池的电量。

测试领域技术分享 5166

Android SELinux——neverallow问题处理(十六)

遇到 neverallow 规则问题,千万别急着去注释/剔除里面原有的规则(原生的尽量别动)。增加 allow 规则是常见的解决办法,但是随着 android 版本的升级,系统对 SELinux 的管控越来越严,增加了大量的 neverallow。一般情况下,向默认标签授予权限的做法是错误的,其中许多权限都是 neverallow 规则所不允许的。按照上面方法去添加 SELinux 可能会违反了 neverallow 规则,编译时候会报 neverallow 相关的错误。

小旭的专栏 2677

基于QT的多线程socket通信

我从上周开始就在找qt的多线程网络通信,结果网上都是啥,有的就是纯理论,有的就是很简单的一对一,最好的就是我找到的伪多线程通信,为什么说它是接近的呢,因为它的开socket是多线程的,但是收发是单线程的,也就是说服务端只能收,客户端只能发,我在此基础上改造了一下,变成了也能同时收发的,我感觉这个例子就比较全了。 我用https://github.com/licongxing/WinIPC_Soc...

Sona的绯闻男友的博客 3608

泰凌微8258入门教程——导读

基于泰凌微TLSR8258 Bluetooth® SIG Mesh 的入门系列教程

2万+

探索Qt多线程TCP通信的无限可能

探索Qt多线程TCP通信的无限可能 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在现代应用程序开发中,网络通信和多线程处理是两个至关重要的技术领域。特别是在使用Qt框架进行开发时,如何在非主线程中实现高效、可靠的TCP通信,是许多开发者面临的挑战。为了帮助开发者更好地掌握这一技术,我们推出了Qt多线程TCP通信Demo项目。 这个项目提供了一个简单而实用的Qt示例,...

gitblog_09743的博客 605

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: Qt 信号与槽
下一篇: C++中string、char *、char[]、const char*的转换
hebbely
博客等级 码龄11年 921粉丝 133原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值