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()都干了什么具體的東西