connect信号槽的异步性导致多线程中的数据被更改及Qt::BlockingQueuedConnection作用

news/2025/2/5 20:45:45/

目录

1. 问题现象       

2. 原因分析

3. 解决方法


1. 问题现象       

       因为业务需求,需要利用子线程向主线程发送数据。像这种子线程和主线程进行数据交互时,一般都是通过Qt的信号槽机制来实现。如下代码:

void myClass::doBusiness()
{...... // 其它代码略connect(this, &myClass::mySignal, m_pBusiness, &CMyBusiness::processBusiness);// 开启业务数据线程auto pDataThread = new std::thread(&myClass::dataThreadFun, this);...... // 其它代码略}// 数据线程函数
void myClass::dataThreadFun()
{// 无限循环,一直处理业务while (true){...... // 其它代码略char* p = data; // data数据在while的每轮循环中都会被更改emit mySignal(p);}
}// 业务处理类,位于主线程
void CMyBusiness::processBusiness(char* pData)
{// 取出pData做一些处理
}

其中m_pBusiness为CMyBusiness类对象,在线程函数dataThreadFun中的以参数p发送信号mySignal,以让CMyBusiness类的processBusiness(char* pData)得以执行,但测试发现,在processBusiness函数中,参数pData和mySignal信号发送过来的数据不一样,数据被更改了。

2. 原因分析

      问题的原因是第5行connect信号槽时,采用默认连接方式,即Qt::AutoConnection方式,Qt官方对该方式的说明如下:

(Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.

即:如果接收信号的对象和发送信号的对象位于同一个线程,则采取Qt::DirectConnection连接;否则就采取Qt::QueuedConnection方式。当信号被发送时,Qt会探测以决定采取Qt::DirectConnection连接方式还是采取Qt::QueuedConnection连接方式。

       对上面的代码段,CMyBusiness即为接收信号的对象,m_pBusiness位于主线程,发送信号对象位于子线程,根据上面的说明,所以第5行的connect采取的是Qt::QueuedConnection连接类型。而Qt对Qt::QueuedConnection的解释如下:

The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.

意思是说:当控制返回接收对象的事件循环时,槽函数才会被执行,槽函数是在接收者所在线程执行的 。也就说Qt::QueuedConnection连接模式就是把信号(类似事件)放到接收者的事件队列中,仅仅只是放入,但不是立即执行,而是等循环到该信号(事件)时才执行,这就会和上面代码的dataThreadFun表示的子线程产生一个时间差,就是在这个时间内,数据被更改了,其是通过上面代码的22行更改的。

3. 解决方法

       解决该问题的方法是上面第5行的connect函数最后一个参数,不要采用默认的Qt::AutoConnection连接方式,而是采用Qt::BlockingQueuedConnection连接方式。Qt官方对Qt::BlockingQueuedConnection解释如下:

Same as Qt::QueuedConnection, except that the signalling thread blocks until the slot returns. This connection must not be used if the receiver lives in the signalling thread, or else the application will deadlock.

意思是说:同Qt::QueuedConnection类似,唯一不同的是:发送信号的线程将会一直阻塞,直到接收信号的槽函数执行后才继续往下执行。这种连接方式不能用于接收信号的对象和发送信号对象都在同一个线程的情况,否则会引起死锁。

        采取Qt::QueuedConnection连接方式后,上面的子线程dataThreadFun在发送信号后会阻塞,直到CMyBusiness类的processBusiness函数执行后才继续往下执行,所以数据就不会被更改。

Qt::BlockingQueuedConnection连接方式不能用于接收信号的对象和发送信号对象都在同一个线程的情况,否则会引起死锁,这很好理解,如果位于同一线程,就会造成你等我,我也等你,大家相互等待对方执行完后再执行,就会造成死锁。


http://www.ppmy.cn/news/1274978.html

相关文章

Mybatis练习

文章目录 配置文件实现CRUD环境准备查询所有数据编写接口方法编写SQL语句编写测试方法起别名解决上述问题使用resultMap解决上述问题小结 查询详情编写接口方法编写SQL语句编写测试方法参数占位符parameterType使用SQL语句中特殊字段处理 多条件查询编写接口方法编写SQL语句编写…

第七章 绘制3D图表和统计地图

7.1 使用mplot3d绘制3D图表 7.1.1 mplot3d概述 mplot3d是matplotlib中专门绘制3D图表的工具包,它主要包含一个继承自Axes的子类Axes3D,使用Axes3D类可以构建一个三维坐标系的绘图区域。matplotlib可以通过两种方式创建Axes3D类的对象:一种方式是Axes3D()方法,另一种方式是…

C++设计模式之——命令模式

命令模式 概念创建步骤示例示例一代码实现运行结果 示例二代码实现运行结果 示例三示例代码运行结果 示例四代码实现运行结果 应用场景 概念 命令模式是一种行为型设计模式,它允许将请求封装为一个对象,从而使得可以参数化客户端请求、将请求排队或者记…

阿里云登录镜像仓库报错: Error response from daemon: Get https://

阿里云登录镜像仓库报错: Error response from daemon: Get https:// 1. 故障现象 开发反应自用笔记本连接镜像仓库是正常的,但通过服务器连接镜像仓库一直失败. 报错信息如下: Error response from daemon: Get https://registry.cn-hangzhou.aliyuncs.com/v2/: unauthoriz…

docker-compose安装nacos和msql

docker-compose安装nacos和msql 前言前提已经安装docker-compose,如果没有安装,则可以查看上面系列文章中的安装教程。并且文章中使用的是mobaxterm连接虚拟机。 1、下载2、创建并运行 前言 前提已经安装docker-compose,如果没有安装&#x…

论文阅读:Learning sRGB-to-Raw-RGB De-rendering with Content-Aware Metadata

论文阅读:Learning sRGB-to-Raw-RGB De-rendering with Content-Aware Metadata Abstract 大多数的 Camera ISP 会将 RAW 图经过一系列的处理,变成 sRGB 图像,ISP 的处理中很多模块是非线性的操作,这些操作会破坏环境光照的线性…

采购审批工作流程快速指南

对很多人来说,控制每一分钱的支出是一件棘手的事情,但在当下充满不确定性的环境里,这一点与收入增长同等重要。正如俗话说:要想赚钱,先学会花钱。 本文将分析支出控制的基石之一:采购审批工作流程。有了审…

【图像分类】【深度学习】【Pytorch版本】 ResNeXt模型算法详解

【图像分类】【深度学习】【Pytorch版本】 ResNeXt模型算法详解 文章目录 【图像分类】【深度学习】【Pytorch版本】 ResNeXt模型算法详解前言ResNeXt讲解分组卷积(Group Converlution)分割-变换-合并策略(split-transform-merge)ResNeXt模型结构 ResNeXt Pytorch代码完整代码总…