标题:求问QSerialPort在多线程环境下如何使用?
作者:johnyork
日期:2015-05-16 23:28
内容:
我想在子线程中使用QSerialPort对象接收串口的数据,而在主线程中根据UI信号(如鼠标点击,等)用同一个QSerialPort对象向同一个串口发送命令,并且在串口长时间无数据接收的时候还可以在主线程强制close该对象,从而可以使子线程正常结束。
我尝试过在主线程中创建QSerialPort对象,然后在子线程中调用waitForReadyRead及read函数来读取从串口接收的数据,但似乎在某些情况下存在无法触发waitForReadyRead返回的问题,在Qt.io论坛上咨询后说是线程相关的问题,但未给出明确的解决方案。
浏览QSerialPort相关的帖子后,有一个说法是:QSerialPort对象必须在子线程中创建;于是我尝试了在子线程中new QSerialPort,虽然表面上看接收数据正常了,但是在主线程中打开或关闭端口时,QtCreator控制台均会显示3条消息:QWinEventNotifier: Event notifiers cannot be enabled or disabled from another thread,这说明调用方法中仍然存在问题。
PS:有人曾问过为什么不使用asynchronous mode,这是因为考虑到串口接收的数据其传输速率有点高(使用的MOXA串口卡),QSerialPort的asynchronous mode是在主线程的事件循环中完成数据的发送和接收,当UI显示控件较多或较复杂时,UI的绘制和渲染可能导致因数据接收延时而造成串口内部缓冲区溢出,或者接收数据丢失。因此,为尽可能降低数据丢失的概率,只能将数据接收工作置于子线程中,并应用QSerialPort的synchronous mode。
想问的问题:
1.有没有哪位高手遇到过和我类似的需求?有没有成功实现过?
2.成功实现过的高手,可否共享一下您关于QSerialPort的使用方法?[ ..
#1 [liulin188 05-17 00:36]
和楼主同感啊,个人很不喜欢Qt那一套异步机制。我就喜欢阻塞同步+多线程来实现。
我写的多线程QextSerialPort都是在线程run函数里定义一个局部的栈对象
QextSerialPort extSerialPort;
就没有那个警告了。
#2 [liulin188 05-17 00:38]
忘了提醒楼主一点,Qt自己的串口类问题很多很多,建议楼主使用第三方那个。。。
#3 [realfan 05-18 09:27]
这个供参考,我写的多线程使用串口封装类。按自己的需要,局部调整一下就行了。
http://www.qtcn.org/bbs/read-htm-tid-58308.html
#4 [johnyork 05-19 00:24]
谢谢各位高手的耐心回复。
我找了最新版的QextSerialPort(v1.2.0版,GitHub上下载的)来看,发现它除了提供事件驱动的非阻塞模式外,似乎没提供阻塞模式的串口API(我自己没找到?还是版本不正确?),而只有一个Polling即查询模式,而网上的教程则是用一个QTimer定时在子线程中查询是否有数据可读。不知是真是假,还请 @liulin188 解惑,感谢!
实在找不到QextSerialPort的阻塞模式用法下,我又重新开了一个测试工程并使用最精简的代码来测试Qt自带的QSerialPort,期望是因为我自己的代码导致的串口程序,没想到居然顺利接收了,再也没有遇到我之前碰到的无法触发waitForReadyRead返回的问题。最后仔细检查代码,重新看了一下Qt关于信号和槽的说明(因为原工程的接收线程中向主线程发射了信号),发现是因为在子线程中向主线程发射信号时传递参数使用的是栈上的临时对象造成的:子线程发射信号后并不会等待主线程中对应的槽函数执行,而是继续执行后面的工作,因而轮到主线程中的槽函数执行时,其传入的参数对象可能早就被销毁了,从而引起了内存访问越界,导致后面稀奇古怪的问题。
@realfan 您好,您的代码我大概看了一下,很有参考价值,非常感谢!
#5 回 johnyork 的帖子 [realfan 05-19 09:27]
johnyork:谢谢各位高手的耐心回复。
我找了最新版的QextSerialPort(v1.2.0版,GitHub上下载的)来看,发现它除了提供事件驱动的非阻塞模式外,似乎没提供阻塞模式的串口API(我自己没找到?还是版本不正确?),而只有一个Polling即查询模式,而网上的教程则是用一个QTimer定时在子线程中查 .. (2015-05-19 00:24)
QextSerialPort的CPU占用率太高了。
能用QSerialPort,还是尽量用Qt自带的吧