Qt源码学习之路(2) QCoreApplication(1)

QCoreApplication最重要的函数便是exec(),我们便从这个函数开始分析QCoreApplication都干了什么。

先列出exec()函数的源码

static int exec();//函数声明

/*!

    Enters the main event loop and waits until exit() is called.
    Returns the value that was set to exit() (which is 0 if exit() is
    called via quit()).

    It is necessary to call this function to start event handling. The
    main event loop receives events from the window system and
    dispatches these to the application widgets.

    To make your application perform idle processing (by executing a
    special function whenever there are no pending events), use a
    QTimer with 0 timeout. More advanced idle processing schemes can
    be achieved using processEvents().

    We recommend that you connect clean-up code to the
    \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in
    your application's \c{main()} function because on some platforms the
    exec() call may not return. For example, on Windows
    when the user logs off, the system terminates the process after Qt
    closes all top-level windows. Hence, there is no guarantee that the
    application will have time to exit its event loop and execute code at
    the end of the \c{main()} function after the exec()
    call.

    \sa quit(), exit(), processEvents(), QApplication::exec()
*/
int QCoreApplication::exec()//函数定义
{
    if (!QCoreApplicationPrivate::checkInstance("exec"))
        return -1;

    QThreadData *threadData = self->d_func()->threadData;
    if (threadData != QThreadData::current()) {
        qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
        return -1;
    }
    if (!threadData->eventLoops.isEmpty()) {
        qWarning("QCoreApplication::exec: The event loop is already running");
        return -1;
    }

    threadData->quitNow = false;
    QEventLoop eventLoop;
    self->d_func()->in_exec = true;
    self->d_func()->aboutToQuitEmitted = false;
    int returnCode = eventLoop.exec();
    threadData->quitNow = false;
    if (self) {
        self->d_func()->in_exec = false;
        if (!self->d_func()->aboutToQuitEmitted)
            emit self->aboutToQuit(QPrivateSignal());
        self->d_func()->aboutToQuitEmitted = true;
        sendPostedEvents(0, QEvent::DeferredDelete);
    }

    return returnCode;
}

我们先看函数声明,它是一个static函数这也就意味着我们在一个Qt进程中只能有一个QCoreApplication,exec()函数只需调用一次(猜想后续深入研究)

再看函数定义,在解析函数定义之前我们先看下函数的注释信息,这有助于我们去分析函数定义。

注释信息主要说了这个函数会开启主事件循环并且进入阻塞状态,直到exit()函数被调用,返回值exit()函数设置的值。

所谓的事件循环其实就是信号槽机制的本质,只有开启事件循环之后,信号槽才能起作用。

注释最后说了我们的析构处理最好不要放在main函数中exec()调用之后执行,因为exec()有可能会不返回。它举了个例子,没有太看懂,它说当用户注销时,系统会先关闭Qt程序的顶级显示窗口,然后终止进程,这是不能保证exec()函数会有返回。我的看法是,它这个例子是说我们关机,强制注销电脑时,操作系统会先关掉我们程序的显示界面再强制终止程序的进程,这个时候exec()可能是没有返回的,一般我们程序都关掉了也不会有什么其他的处理了,当然如果你要是想在主线程注销时写日志的话可能就得按照它所说的去做了,将后续的处理函数与aboutToQuit()信号绑定,那么在将要关闭主事件循环时,它会发送这个信号来调用你的处理函数而不必去等待exec()的返回了。

接下来我们继续分析exec()函数的定义。

函数开头做的一件事是去检查QCoreApplication的对象是否存在,如果不存在则返回。

QThreadData是存储线程数据信息的一个类,有点像是线程的句柄,但是它里面存储的信息要比句柄多。判断当前线程是否是主线程,如果不是则返回同时提醒用户。

也就是说我们的QCoreApplication的定义必须是在main()函数所在的主线程中。

然后判断主事件循环是否已经开启了,如果已开启则返回。

接下来就是一些数据信息的赋值了,将线程的退出信息quitNow置为false,将exec()是否已经调用置为true,将我们前面说过的aboutToQuit信号是否发射置为false

然后便是定义一个EventLoop对象,它是主事件循环对象,调用eventLoop.exec()开启主事件循环,并进入阻塞状态等待返回。

当主事件循环关闭并返回之后,则发送aboutToQuit信号,然后exec()函数结束并返回从主事件循环那儿得到的返回值。整个exec()的完整流程便结束了。

这篇就分析到这里,下篇继续分析QEventLoop的exec()都干了什么具体的东西。


展开阅读全文

没有更多推荐了,返回首页