Qt中QSerialPort使用时内存泄漏问题与解决

1 问题描述

在开发一个瞄准系统,包含的头瞄功能中,需要实现云台实时随动。要求:1、用串口读取IMU的数据,获取实时姿态;2、用另一个串口控制云台实时随动。
单独测试云台头瞄时程序正常运行,但放入瞄准系统后(系统整体还包含图像显示、处理等功能)会Qt应用出现不定时闪退,具体表现为:

启动应用后,程序起初可以正常读取IMU数据并进行头瞄;
经过不定长的时间后(一般为几秒到十几秒),程序闪退;
Qt窗口自动关闭,控制台没有任何报错或警告提示,退出代码为-1073740940

2 代码诊断与解决方法

奇怪的退出代码一般都是内存泄漏问题,但网上没有找到类似的问题,由于云台转动功能之前就有,推断问题出在IMU数据读取上。
CSDN上找到有在死循环内添加依据qApp->processExecute()解决的,但这个方法在这个系统上没有用,不过我的代码和他的代码有一点不同:
我的代码在读取IMU数据时,是直接从串口读取的(由于IMU数据发送频率很高,不需要担心缓存区没有数据,即使没有也可以用循环来等待),且使用waitforReadyRead()的方式不对,具体如下

while(1)
{
	serialport->waitforReadyRead(10);
	buffer=serialport->read(1).toHex();
	while(buffer.length()<1)
	{
		serialport->waitforReadyRead(10);
		buffer=serialport->read(1).toHex();
	}
	...
	...
}

而网上找到的串口读取部分代码为

while(1)
{
	if(serialport->waitforReadyRead(10))
		buffer=serialport->readAll();
	...
	...
}

问题就出在waitforReadyRead(),它不是如sleep_for()这样的延时,而是有bool类型返回值的。返回true则说明缓存区有数据,可以读出。
这时又有问题:
IMU的帧是有长度的,我不需要readAll(),
而一个个字节读又太慢(每读一字节都要用waitforReadyRead()判断一下会很耗时),
一次性读取所需的长度又不能保证缓存区真的有那么多字节(实验发现如果不加判断一直读串口,读若干次后会出现读到字节数一直是0的情况)

此处,通过如下策略即可解决:waitforReadyRead()后,读取所需长度(数据帧长度),判断得到的长度够不够,如果不够再等待后读取剩余长度,直至一帧读完。

3 其他问题

问题的出现其实是IMU读取和图像显示同时开启后出现的。图像显示的线程通过QTimer实现。
当图像显示时,IMU串口读取速度显著变慢,原本每秒100帧数据现在也只能读到30帧,导致头瞄和随动滞后,但其实并没有丢失数据,每隔一段时间利用readAll()清空缓存区后就能立刻读到IMU的最新数据。
这里我推测是QTimer的中断导致了阻塞,因为很明显看出串口读数据时每隔2~3帧,读取速度就会显著变慢一次(即QTimer的timeout中断一次,就会导致IMU读取变慢一次),但目前还没有什么解决的办法,欢迎Qt大佬来讨论。

你可能感兴趣的:(多线程,qt,c++,串口通信)