先说重点,先了解几个重要的概念,
话不多说,直接上源码,清晰的将事件循环与线程的关系通过代码的方式展现出来
主线程的事件循环是由下面的代码触发
QCoreApplication::exec()
exec的内部实现如下:
int QCoreApplication::exec()
{
...
QEventLoop eventLoop;
int returnCode = eventLoop.exec();
...
return returnCode;
}
通过上面的代码可以看到,定义了一个QEventLoop对象,对该对象调用了exec方法。QEventLoop的exec简要实现如下:
int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
...
while (!d->exit)
processEvents(flags | WaitForMoreEvents | EventLoopExec);
...
return d->returnCode;
}
由上可以看出,QEventLoop下的exec调用了processEvents方法。该方法的实现如下:
bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
if (!d->threadData->eventDispatcher)
return false;
if (flags & DeferredDeletion)
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
return d->threadData->eventDispatcher->processEvents(flags);
}
由上可以看到在processEvent的实现中,首先判断了threadData中成员eventDispathcer是否存在,若不存在,则返回false,eventDispatcher从字面意思理解,是一个事件分发器,通过该对象指针调用其方法processEvents,到这里会有一个疑问,eventDispatcher是何时创建的呢?请看下面的代码:
QEventLoop::QEventLoop(QObject *parent)
: QObject(*new QEventLoopPrivate, parent)
{
Q_D(QEventLoop);
if (!QCoreApplication::instance() && QCoreApplicationPrivate::threadRequiresCoreApplication()) {
qWarning(
"QEventLoop: Cannot be used without QApplication");
} else {
d->threadData.loadRelaxed()->ensureEventDispatcher();
}
}
QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data)
{
Q_UNUSED(data);
#if defined(Q_OS_DARWIN)
bool ok = false;
int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
if (ok && value > 0)
return new QEventDispatcherCoreFoundation;
else
return new QEventDispatcherUNIX;
#elif !defined(QT_NO_GLIB)
const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
if (qEnvironmentVariableIsEmpty(
"QT_NO_GLIB")
&& (isQtMainThread || qEnvironmentVariableIsEmpty(
"QT_NO_THREADED_GLIB"))
&& QEventDispatcherGlib::versionSupported())
return new QEventDispatcherGlib;
else
return new QEventDispatcherUNIX;
#else
return new QEventDispatcherUNIX;
#endif
}
可以看到,eventDispatcher是在QEventLoop对象构造的过程中创建的,注意在这里生成的eventDispatcher已经是QEventDispatcherUnix类型了。下一步就是列出事件调度器的核心实现了,这里以linux为里介绍,所以QEventDispatcherUNIX下的实现processEvents实现,源码如下所示:
bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherUNIX);
……
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
……
timespec *tm = nullptr;
……
d->pollfds.append(d->threadPipe.prepare());
int nevents = 0;
switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)) {
……
}
return (nevents > 0);
}
void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type,
QThreadData *data)
{
……
while (i < data->postEventList.size()) {
……
const QPostEvent &pe = data->postEventList.at(i);
++i;
……
QEvent *e = pe.event;
QObject * r = pe.receiver;
……
QCoreApplication::sendEvent(r, e);
}
……
}
通过上面的代码可以看出,在事件调度器里面的processEvents实现中,首先调用sendPostedEvents方法将事件队列中的事件通过QCoreApplication::sendEvent调用发送给对应的对象,这里简要的提一下,sendevent方法是一个阻塞型的方法调用,仅用于本线程内的调用,他的内部内部核心实现是函数调用,即通过接收对象receiver的指针调用该对象的event方法,但是需要注意的是在调用event方法之前首先要调用该对象注册的事件监听器对象eventfilter方法。我会单独列出一个文章讲解sendevent,详细实现将在里面实现。
然后后调用了poll相关的方法,里面射击了threadPipe的相关用法,我通过查看资料了解到的是下面的实现会导致该循环让出cpu,等待事件队列中有属于再进行工作,这一块我需要再研究下后续补充。
至此,我们了解了一个事件循环的本质及与事件循环与线程的关系: