一 前言:

最近我开发了一个QT上位机应用程序。该应用程序通过串口接收来自下位机的数据,并将下位机处理后的数据结果显示在用户界面上。下位机每隔200毫秒向QT上位机发送一帧包含20字节的数据。然而,在这一过程中,程序经常出现界面卡顿和崩溃的问题。虽然可以通过降低下位机数据发送频率(例如,每1秒发送一帧数据)来避免这一问题,但这种解决方案并不理想。为了更优雅地处理这一问题,我采用了QT的多线程机制——在GUI线程之外,创建了一个专用的子线程来处理串口数据。


二 步骤

2.1 方法描述

​QThread 类提供了一个与平台无关的管理线程的方法。一个 QThread 对象管理一个线程。QThread 的执行从 run() 函数的执行开始,在 Qt 自带的 QThread 类中,run() 函数通过调用 exec() 函数来启动事件循环机制,并且在线程内部处理 Qt 的事件。在 Qt 中建立线程的主要目的就是为了用线程来处理那些耗时的后台操作,从而让主界面能及时响应用户的请求操作。具体操作步骤如下:

  1. 定义一个继承于 QObject 的 worker 类,在 worker 类中定义一个槽函数 doWork(),这个函数中接收和处理串口数据,并将处理好的数据发送给GUI线程。
  2. 在GUI线程的 controller 类中,新建一个 QThread 的对象和 woker 类对象,使用 moveToThread() 方法将 worker 对象的事件循环全部交由 QThread 对象处理。
  3. 建立相关的信号函数和槽函数进行连接,GUI线程发出信号触发 QThread 的槽函数处理串口数据,数据处理完毕后QThread 子线程发送信号触发GUI线程槽函数接收处理好的串口数据。

2.2 代码实现

2.2.1 子线程中

1.新建一个继承与QObject的子线程类:SerialWorker
image-20230614110031377
2.修改serialworker.h
image-20230614110849762
3.修改serialworker.c
image-20230614111637763

2.2.2 GUI线程中

1.修改widget.h
image-20230614112946267
2.修改widget.c
image-20230614120706073


三 总结

经过测试,采用子线程处理串口数据收发操作能够显著提高程序的运行稳定性,并有效解决了因串口数据量过大而导致的界面卡顿问题。
除了创建专门的串口数据处理线程之外,还可以通过异步处理数据的方式来防止界面崩溃。具体做法是,在接收到串口数据后,不立即进行数据处理,而是将数据暂存至队列中,并采用异步机制进行后续处理。这样不仅可以减轻主线程的负担,还能避免因数据处理过程中的延迟而导致的用户界面响应迟缓或崩溃。


参考博客:
QT 中的多线程—moveToThread 篇 - 知乎 (zhihu.com)
Qt子线程、多线程使用串口 QSerialPort QThread QObject_qt 串口多线程_超级大洋葱806的博客-CSDN博客

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐