背景:
1 移植LINUX下C语言的程序到WIN下QT环境,然后再移植到LINUX的QT环境生成执行程序。
2 主线程使用moveToThread()创建子线程。
3 子线程初始化时,创建串口,打开串口,while(true)接收串口数据。
想实现主界面点击按钮,让串口线程发送一包报文。
按以往的经验就是,主线程调用子线程函数,子线程函数内发送信号,自己接收信号进入槽函数进行发送报文,这样可以做到发送在子线程进行不影响主线程。
问题来了:主线程的调用进入到子线程后,没有进入槽函数。
最后发现原因:子线程在初始化时打开了while(true),整个线程处在卡在循环状态,后续再进入的操作都不会触发。
走的冤枉路:1、 首先想到的是连接问题,先去排查了信号槽的建立是否有问题,排查后确定没问题。只要connect参数没错,信号槽参数没错,几乎不会有问题。
2、有可能跨线程导致槽函数没进入。这个也是以前遇到的坑,但是已经特意使用调用子线程函数,然后发信号的方式规避了。
3、最大的坑来了:猜测是否是类的创建有问题,类继承QObject,就不好使。换成有界面类型继承QWidget试了下,发现软件启动卡死,暂时关掉接收循环,发现发送成功了,当时完全搞迷糊了,后来明白了才发现有多低级。
当时在测试换成继承QWidget类时,就预感自己走弯路了,但是实在没想出来原因,只能硬着头皮继续查。最后发现主线程的ID和子线程的ID是一样的,说明根本就没开辟子线程,所以启动while循环时卡死了。说明继承QWidget带UI界面的类,使用moveToThread不好使。
然后发送好使是因为while关掉了,自然好使。
总结:以前使用QT时没发现这个问题,是因为以前使用QT的串口接收,调用的是信号槽,当收到信号readyRead(),就进入槽函数解析。这不同于while循环,不会造成卡死。所以以前的串口接收发送都写到一个cpp里。
现在要移植到linux下的QT,无法使用QT自带的串口类,所以忽略了这个问题。
其次是LINUX下C语言写的串口通讯和C++还是有区别,C语言没有类,可以直接创建一个线程专门供while循环接收数据,而其他发送在线程外。C++是一个线程专门给一个类使用,循环就造成整个类的函数都不能再运行。