QT 多线程 串口通信
Qt的子线程写法:
1、不要写死循环!需要持续做的事情,做个timer,绑到timeout信号上
2、写一个object,将其moveToThread(movetothread法)
3、该object,对外的所有操作,全部用信号槽。通过槽接收外部的调用操作(比如open、close、write),通过信号发送数据给外部(比如接收到的数据)
4、需要在子线程分配的资源,比如QSerialPort,全部在该object的某个槽函数(如init)中进行,将该槽函数绑定到线程的started信号上。moveToThread()并不是将整个worker 对象“搬移”到QThread线程中,而是将connect中的槽函数放到QThread线程中执行。
5、程序退出时,不要直接delete object,因为那个对象不处于子线程。在需要退出时,执行object的deleteLater函数(直接调用或通过信号槽触发均可),这样就会由它所属的线程负责delete这个object。然后将object的destroyed信号,绑定到线程的quit槽上,将线程的finished信号绑定到QThread对象的deleteLater槽上。这样,销毁流程就是->子线程删除object->线程停止->线程对象销毁
6、线程对象,以及move到线程里的对象,都不要设置parent
7、Qt 4.8之后,可以把线程的finish信号直接绑到对象的deleteLater上,QThread会保证在子线程中删除这些对象。
8、new对象时不要输入parent指针,原因就如你写的这句qWarning。init函数不直接调用,而是ThreadObj* obj = new ThreadObj; obj->moveToThread(thread); connect(thread, &QThread::started, obj, &ThreadObj::init),这样init方法就可以保证在子线程中执行,然后在那里面再初始化obj的成员对象
9、串口有QSerialPort类,绑定readyRead信号就行。其他要一直死循环的,做个singleshot的定时器,执行结束后重新start,timeout写0就行
10、io操作在驱动层不是由用户线程执行,用户线程如果调waitforbyteswritten就是阻塞等待,不调用的话就是非阻塞,然后通过系统消息来触发信号槽。只要你不是queuedConnection,而是默认的directConnection,槽函数就会在信号发起的位置直接回调执行
11、写个类操作QSerialPort,类成员放个QSerialPort指针,对外交互的函数都写成槽,再写一个init函数,然后,在你构造这个类的地方,也构造一个QThread,将类对象moveToThread(thread),thread->start()
从此,所有通过信号槽执行的该类函数,都会在子线程里运作:具体实现->将thread的started信号绑定到obj的init函数上,init函数里进行new QSerialPort和openPort
读操作,把QSerialPort的readyRead信号绑到这个obj的槽上。槽里调用read,然后把读的结果用信号emit到外部
写操作,在类里提供一个write槽函数,函数内直接调用串口类的write。外部使用时,外部emit一个信号,该信号触发obj的write槽函数
-
Qt::DirectConnection(直连方式)(信号与槽函数关系类似于函数调用,同步执行):当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。
-
Qt::QueuedConnection(排队方式)(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行):当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。

浙公网安备 33010602011771号