Qt串行端口的C++线程模式
C++ Threading Pattern for Qt serial port
我的目标是在不阻塞主线程(GUI)的情况下从串行设备接收消息,并尝试将依赖于平台的逻辑(GUI和串行端口)与业务逻辑(处理消息)分离,以便于移植到其他平台
上下文:我正在使用Qt和QtSarialPort模块。消息协议很简单,0xff用于结束每条消息。
到目前为止,我已经找到了4个解决方案:
方法1:
-
使用一个线程读取串行端口并填充缓冲区
-
使用另一个线程读取缓冲区,提取有效消息(到另一个缓冲区?还不确定这将如何工作)
-
使用另一个线程解析消息
方法2:
-
使用一个线程读取串行端口,并将有效消息提取到缓冲区中
-
使用另一个线程解析消息
方法3:
- 使用一个线程读取串行端口,提取一条有效消息,并阻塞直到该消息得到处理,利用QtSerialPort的内部读取缓冲区缓冲传入数据
方法4:
- 使用主线程异步读取串行端口,提取一条有效消息,并为每条消息生成一个新线程来处理它们
方法1、2和3的不同之处在于一般工作负载划分为的线程数,尽管我不知道哪一个最好。
我目前使用的是方法4,它效率非常低,在低端计算机上运行不好,因为产生了大量的线程,每次我移动或与GUI交互时,串行通信都会停止。为每条消息生成一个线程也会使消息的顺序变得不确定,这到目前为止还不是一个大问题。。。
还有其他方法吗?每种方法的优点(如果有的话)和缺点是什么?哪种方法最好用?谢谢
EDIT:在主线程中处理消息的一个问题是,与GUI交互(甚至移动窗口)会阻塞消息处理功能。有办法解决这个问题吗?
我认为使用多线程可以获得两个主要优势:
- 避免由于GUI处理例程被串行端口处理例程搁置而导致GUI性能不佳
- (也许更重要)当GUI例程将串行数据读取例程延迟太久时,避免缓冲区溢出导致的串行数据丢失
您应该只需要生成一个线程。只要让线程在进入时从串行端口读取数据(通过将QSerialPort的readyRead()信号连接到QSerialPort对象上调用read()的插槽),然后在它想向GUI发送一些串行数据时发出一个信号(带有QByteArray参数)。您的主/GUI线程可以通过QueuedConnection接收数据,该连接不会阻塞串行线程或主/GUI螺纹。
这几乎就是它的全部;唯一需要担心的是彻底关闭。请确保有另一个跨线程信号/插槽连接到QThread的quit()插槽,这样,当该退出时,您可以发出该信号,然后在QThread上调用wait(),等待它退出响应。一旦wait()返回,就可以安全地删除QThread对象。
您可以通过简单地依赖Qt事件循环来避免额外的线程(到目前为止,只有当串行端口实际接收到消息时,主线程,也就是处理要清除的GUI的线程,才会被阻止)。
否则,如果您想在专用线程中完全处理串行端口,那么解决方案是实现一个从QThread
派生的类,然后用以下内容覆盖run()
函数:
void MyClass::run()
{
QSerialPort port;
// ... serial port initialization here
// Connect signals/slots
connect(&port, SIGNAL(readyRead()), this, SLOT(readData()));
port.open();
// Start a new message loop on this thread
exec();
}
其中,readData
是在MyClass
中实现的用于处理接收到的数据的功能。由于port
由新线程(在run()
中创建)所有,因此其事件将由线程本身处理(以相对于主线程完全独立的方式)。
如果你想在某个时候与主线程通信(例如:你在串行上收到了一些东西,这应该会导致你的GUI发生变化),那么你仍然可以使用Qt的信号/插槽。只需在MyClass
上实现一个信号,并在主线程(例如:您的主窗体)处理的对象上实现插槽:然后只需连接MyClass
的信号和主窗体上的插槽,就完成了:signals/sslots是Qt中跨线程通信的解决方案。
您还可以避免使用任何(额外的)线程,并利用Qt事件循环。阅读活动,QioDevice;则Qt将把你的设备文件描述符传递给它的多路复用循环(例如轮询(2)…);QSocketNotificationer可能应该(在Posix上)在非套接字文件描述符上工作,就像串行设备一样。
详细信息可能是操作系统特定的
- Visual Studio 发布模式阻止在调试模式下执行的代码.使用 WinHTTP 和多线程
- 多线程程序卡在优化模式下,但在 -O0 中正常运行
- C++中的线程 交错模式
- 如何在另一个线程中关闭 MFC 模式对话框并获取对话框返回值?
- 当主GUI线程被阻塞时,如何从工作线程创建无模式对话框
- 工作线程队列的这种变体是某种模式或通用结构吗?
- COCOS2D-X:从另一个线程中加载精灵,任何模式
- 在用户模式下从另一个进程回调,没有额外的线程
- 这是否可以兑换线程安全的双重检查锁定模式
- C++Win32 在低优先级模式下运行应用程序/线程
- 线程退出时 DLL 中的 MFC 无模式对话框被销毁
- 线程池的设计模式
- 多线程模式下的SQLite3:执行到底不安全
- 在多个相互依赖的线程上进行封送处理和等待的算法、模式或最佳实践
- 避免忙于等待,并在实时和非实时线程之间切换模式
- 考虑 CPU 提升模式的多线程超线性性能实现
- 用户模式计划程序线程的最大数量
- Qt串行端口的C++线程模式
- 在多线程代码中缓存友好的数组迭代模式
- 释放模式下的boost线程崩溃