一、什么是Qt消息循环
Qt消息循环,就是从一个队列中不断取出消息,并响应消息的过程。窗体的鼠标、键盘、输入法、绘制,各种消息,都来自于Qt的消息循环。以Windows操作系统为例,Qt接管Windows原生窗口消息,并翻译成Qt的消息,派发给程序下的各个子对象、子QWidget等,通过接管层,可以很好屏蔽不同平台之间的差异性,开发人员不需要关心Windows或者X11的消息的差异性,只需要搞清楚各个QEvent之间是什么含义。
最开始的Qt消息循环开始于QCoreApplication::exec()。用户创建出一个QCoreApplication,或者说更多情况下是QApplication,执行QCoreApplication::exec(),一个应用程序便开始了。QCoreApplication会不断从操作系统获取消息,并且分发给QObject。
如果没有消息循环,那么Qt的信号和槽无法完全使用,有些函数也无法正确执行。举个例子,通过QueuedConnection连接的信号,其实是将一个事件压入了消息循环,如果没有QCoreApplication::exec(),那么这个消息循环将永远无法派发到指定的对象。
二、什么是线程相关性
准确点来说,应该是指QObject的线程相关性。以Qt文档中的示意图来作说明:
当我们创建一个QObject时,它会与创建自己所在的线程绑定。它参与的消息循环,其实是它所在线程的消息循环,如上图所示。假如某个线程没有默认的QThread::exec(),那么该线程上的QObject则无法接收到事件。另外,如果两个不同线程的QObject需要相互通信,那么只能通过QueuedConnection的方式,异步通知对方线程,在下一轮消息循环处理QObject的消息。
QObject的线程相关性默认会和它的parent保持一致。如果一个QObject没有parent,那么可以通过moveToThread,将它的线程相关性切换到指定线程。
了解QObject的线程相关性非常重要,很多初学者常常分不清一个多线程中哪些QObject应该由主线程创建,哪些应该由工作线程创建,我的观点是,它参与哪个消息循环,就由哪个来创建。
正因为这样的特性,我们才可以理解什么叫做AutoConnection。通过AutoConnect连接的两个QObject,如果是在同一个线程,那么可以直接调用(DirectConnection),如果不是在同一个线程,那么就通过事件通知的方式(QueuedConnection)来调用。通过信号和槽、事件或者QueuedConnection方式来进行线程间的通讯,尤其是与UI线程通讯,永远是最优雅的方式之一。
希望大家看了这篇文章