Qt串口通信 waitForReadyRead函数与waitForBytesWritten函数导致的内存增长问题记录

这段时间做项目需要有一个进行快速采集信息的设备,但是在单独测试的过程中发现程序的内存占用会一直增长,也就是所谓的内存泄露问题。这个问题困扰了我们几个星期,我尝试了通过事件循环重写waitfor系列函数来解决这个问题,但是由于线程包含问题导致了新的问题。。。今天在Qt的官方论坛上搜索时发现15年就有人发现了这个问题,然后上传了bug库并得到了解决,所以特此记录。

1.问题描述

 通过形如下面的代码进行串口的读取或者写入(高频率),会导致运行exe的内存占用不断提升,在一定时间后内存泄露到一定程度会导致软件崩溃。

while (1) 
{
	if (port.waitForReadyRead(10)) 
	{
		port->readAll();
	}
}

2.问题原因分析

 因为waitfor系列函数是通过readyRead()信号与bytesWritten()信号来实现的,如果产生这两个信号过快(就像上面的代码,死循环执行疯狂产生信号),会导致对应到槽函数的事件(信号到槽的执行是一种事件,我之前写过,这个事件将会到对应线程的消息队列中排队等待执行)一直在消息队列中疯狂阻塞,阻塞的结果就是消息队列不断膨胀,从而内存不断增加,直到队列到达上限导致程序崩溃。

3.问题解决方案

 知道原理后问题解决就很简单了,说穿了就是让线程去执行消息队列中的事件而不是一直产生,而Qt专门为这种情况制定了一个函数:qApp->processEvents(),这个函数的意思就是让调用此函数的线程执行其消息队列中的事件,直至没有事件可以执行为止。可见在死循环中加上这个函数之后,相关的内存泄露问题将迎刃而解,就像下面这样:

while (1) 
{
	if (port.waitForReadyRead(10)) 
	{
		qApp->processEvents();
		port->readAll();
	}
}

后记:真的是一个很简单的问题,但是之前一直没有考虑这么多,真的是很惭愧,毕竟自己以后用Qt的机会将会越来越少,现在居然还碰到这么简单的问题拖了这么久才解决,真的是非常愧疚。不仅是自己能力上的愧疚,还有就是对于解决方案搜素的愧疚,一个15年就在论坛上讨论并提出bug后解决的问题,居然困扰了自己这么久,很是惭愧。
此bug讨论网址:https://forum.qt.io/topic/59472/qtserialport-and-memory-usage
此bug解决方案:https://bugreports.qt.io/browse/QTBUG-48653

  • 34
    点赞
  • 180
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
QT串口通信的接收与发送可以通过QSerialPort类实现。QSerialPort类提供了许多方法来设置串口的参数,打开和关闭串口,读写串口数据等。 接收数据: 1. 首先需要连接QSerialPortreadyRead()信号到槽函数中。当串口有数据可读时,readyRead()信号会被触发。 2. 在槽函数中使用readAll()方法读取串口中的数据,并将其存储到一个缓冲区中。 示例代码: ``` QSerialPort serialPort; serialPort.setPortName("COM1"); // 设置串口名 serialPort.setBaudRate(QSerialPort::Baud9600); // 设置波特率 serialPort.open(QIODevice::ReadOnly); // 打开串口,只读模式 // 连接readyRead()信号到槽函数 connect(&serialPort, &QSerialPort::readyRead, [=](){ QByteArray data = serialPort.readAll(); // 读取串口数据 // 处理接收到的数据 }); ``` 发送数据: 1. 使用write()方法向串口发送数据。 2. 可以使用waitForBytesWritten()方法等待数据发送完成,也可以使用QSerialPortbytesWritten()信号来监测数据是否发送完成。 示例代码: ``` QSerialPort serialPort; serialPort.setPortName("COM1"); // 设置串口名 serialPort.setBaudRate(QSerialPort::Baud9600); // 设置波特率 serialPort.open(QIODevice::WriteOnly); // 打开串口,只写模式 QByteArray sendData = "hello, world"; serialPort.write(sendData); // 发送数据 // 等待数据发送完成 serialPort.waitForBytesWritten(); // 或者连接bytesWritten()信号到槽函数 connect(&serialPort, &QSerialPort::bytesWritten, [=](qint64 bytes){ if(bytes == sendData.size()){ // 数据发送完成 } }); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

方寸间沧海桑田

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值