原文链接:https://www.cnblogs.com/codegb/p/17274163.html
什么是事件循环?
在ChatGPT💬上搜索到的概念是:
在Qt中,事件循环是一种机制,用于处理各种异步事件。事件循环通过一个事件队列来管理和调度事件,当队列中有事件时,事件循环会从队列中依次取出事件并处理,直到队列为空或者事件循环被中断。
事件的产生可以是用户输入、系统信号、网络请求、定时器等,Qt提供了一系列的事件处理函数和信号槽机制,可以方便地将这些事件与具体的操作相绑定。
因此,Qt的事件循环机制是Qt应用程序实现异步响应和多线程编程的基础。
个人理解,Qt的事件循环是通过一个队列来循环处理事件的机制。当队列中有事件时,事件循环会处理事件;如果队列中没有事件,则事件循环会阻塞等待。
事件是如何产生的?
事件的产生可以分为两种:
-
程序外部产生:指系统产生的事件,例如鼠标按下(MouseButtonPress)、按键按下(KeyPress)等,这些事件会在事件发生后以msg格式加入到系统事件队列中。Qt通过捕捉系统事件,从系统事件队列中取出windows下msg格式的事件并将其封装成自己的QEvent类,再将事件发送出去。
-
程序内部产生:指在代码中手动创建一个事件,然后通过sendEvent/postEvent将事件发送到事件循环中。其中,sendEvent是阻塞型的发送方式,会等待事件处理完成后再继续执行;而postEvent是非阻塞型的发送方式,会将事件放入事件队列中,并立即返回。postEvent加入队列的事件被称为发布事件,加入的事件队列是发布事件队列。
事件是如何处理的?
让我们通过一个流程图简单了解事件从发出到处理的过程。
在接下来的解析中,我们将通过分析源代码,逐步验证流程图中的每个步骤。
下面我们将通过分析源码,来揭秘为什么sendEvent/postEvent是阻塞和非阻塞的、以及事件的处理流程。
sendEvent
首先,我们看sendEvent:
bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event)
{
// sendEvent是阻塞调用
Q_TRACE(QCoreApplication_sendEvent, receiver, event, event->type());
if (event)
event->spont = false;
return notifyInternal2(receiver, event);
}
可以看到,sendEvent是调用了notifyInternal2这个函数
bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
...
// Qt enforces the rule that events can only be sent to objects in
// the current thread, so receiver->d_func()->threadData is
// equivalent to QThreadData::current(), just without the function
// call overhead.
// 事件只能在同一个线程被send
QObjectPrivate *d = receiver->d_func();
QThreadData *threadData = d->threadData;
QScopedScopeLevelCounter scopeLevelCounter(threadData);
if (!selfRequired)
return doNotify(receiver, event);
return self->notify(receiver, event);
}
进一步跟踪到其doNotify函数
static bool doNotify(QObject *receiver, QEvent *event)
{
if (receiver == nullptr) {
// serious error
qWarning("QCoreApplication::notify: Unexpected null receiver");
return true;
}
#ifndef QT_NO_DEBUG
// 检查接受线程与当前是否同线程
QCoreApplicationPrivate::checkReceiverThread(receiver);
#endif
// QWidget类必须用QApplication
return receiver->isWidgetType() ? false : QCoreApplicationPrivate::notify_helper(receiver, event);
}
然后就到了咱们这次分析的第一个重点——事件通知:QCoreApplicationPrivate::notify_helper
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
// ...
}
通过分析这个函数,我们就可以大致知道事件处理的几个流程:
- 判断QCoreApplication有没有安装事件过滤器,有就把信号发送到QCoreApplication所安装事件过滤器里,由事件过滤器对事件进行处理。
// send to all application event filters (only does anything in the main thread)
if (QCoreApplication::self
&& receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
filtered = true;
return filtered;
}