Qt源码剖析之事件循环系统
本文基于 Qt6.2 源码进行分析。从主事件循环入手,分析 Qt 事件循环系统的主要实现(部分细节省略)。
主事件循环
主事件循环负责整个 Qt 应用程序接收事件、分发事件的流程,运行在主线程。
写过 Qt 程序的都知道,一般新建一个 Qt 项目会默认生成一个 mian.cpp 文件,内容如下
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
return a.exec();
}
其中 a.exec()
会启动一个事件循环,即主事件循环。所谓的事件循环,简单来说就是在循环中处理事件。接下来我们从 QCoreApplication::exec()
方法入手。
QCoreApplication::exec()
int QCoreApplication::exec()
{
...
QEventLoop eventLoop;
...
int returnCode = eventLoop.exec(QEventLoop::ApplicationExec);
...
return returnCode;
}
我们可以看到,主事件循环是通过调用 QEventLoop::exec(QEventLoop::ApplicationExec) 启动。
事件循环 QEventLoop::exec(ProcessEventsFlags flags)
int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
auto threadData = d->threadData.loadRelaxed();
...
while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec);
...
return d->returnCode.loadRelaxed();
}
从上述代码我们可以看到,事件循环是通过在while循环中不断调用processEvents()
实现的。同时这里值得注意的是事件循环只在当前线程有效,事实上,在主事件循环的exec()
的省略代码中,也有判断当前线程和事件循环所属线程是否一致的代码。
每个线程都可以有自己的事件循环。
QEventLoop::processEvents()
最终的事件循环和处理是在“事件调度器”—QAbstractEventDispatcher
的processEvents
方法实现的。
bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
auto threadData = d->threadData.loadRelaxed();
if (!threadData->hasEventDispatcher())
return false;
return threadData->eventDispatcher.loadRelaxed()->processEvents(flags);
}
不同的系统使用不同的事件调度器。其中类Unix系统使用的是 QEventDispatcherUNIX
,本文基于此类进行分析。
QEventDispatcherUNIX::processEvents()
bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherUNIX);
...
// 调用 sendPostedEvents 发送通过 QCoreApplication