0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Qt中的三個exec之間有什么聯(lián)系

嵌入式小生 ? 來源:嵌入式小生 ? 2023-03-06 09:44 ? 次閱讀

一、導讀

在Qt中,常見到三個exec,第一個是QApplication::exec(),第二個是QEventLoop::exec,第三個是QThread::exec()。本文從源碼角度來看看這三個exec()。

QApplication::exec()是QApplication類下的一個靜態(tài)成員函數(shù),該函數(shù)用于進入主事件循環(huán)。

QEventLoop::exec是QEventLoop類下的一個公共成員函數(shù),用于進入主事件循環(huán)。

QThread::exec()是QThread類下的一個受保護的成員函數(shù),也是用于進入事件循環(huán)。

都是進入事件循環(huán),他們之間有什么聯(lián)系呢,接著后面的分析。

二、QApplication::exec()

在實際開發(fā)中,必須調用QApplication::exec()來啟動事件處理,主事件循環(huán)會從窗口系統(tǒng)接收事件,并將這些事件分派給應用程序小部件。在調用exec()之前不能發(fā)生任何用戶交互,但是存在一種特殊的情況:QMessageBox這樣的模態(tài)小部件可以在調用exec()之前使用,因為模態(tài)小部件會調用exec()來啟動本地事件循環(huán)。

從源碼角度,QApplication::exec()會調用QGuiApplication::exec(),QGuiApplication::exec()會調用QCoreApplication::exec():

intQCoreApplication::exec()
{
//檢查exec實例
if(!QCoreApplicationPrivate::checkInstance("exec"))
return-1;

//獲取線程數(shù)據QThreadData
QThreadData*threadData=self->d_func()->threadData;

//檢查該函數(shù)的調用是否在主線程中,如果不是,則返回。
if(threadData!=QThreadData::current()){
qWarning("%s:Mustbecalledfromthemainthread",self->metaObject()->className());
return-1;
}
//檢查是否存在事件循環(huán),如果存在,則返回,否則繼續(xù)后續(xù)操作。
if(!threadData->eventLoops.isEmpty()){
qWarning("QCoreApplication:Theeventloopisalreadyrunning");
return-1;
}

threadData->quitNow=false;
//創(chuàng)建QEventLoop事件循環(huán)對象
QEventLoopeventLoop;
self->d_func()->in_exec=true;
self->d_func()->aboutToQuitEmitted=false;
//啟動事件循環(huán)
intreturnCode=eventLoop.exec();
threadData->quitNow=false;

if(self)
self->d_func()->execCleanup();

returnreturnCode;
}

從上述源碼可見,QApplication的exec()經過層層調用,最終是使用QEventLoop實現(xiàn)事件循環(huán)。

QApplication::exec()用于啟動應用程序的事件循環(huán),讓應用程序能得以啟動運行并接收事件。

『備注,執(zhí)行應用清理的優(yōu)雅方式』:

建議將清理代碼連接到aboutToQuit()信號,而不是放在應用程序的main()函數(shù)中。這是因為,在某些平臺上,QApplication::exec()調用可能不會返回。例如,在Windows平臺上,當用戶注銷時,系統(tǒng)會在Qt關閉所有頂級窗口后終止該進程。因此,不能保證應用程序有足夠的時間退出事件循環(huán),并在QApplication::exec()調用之后,即在main()函數(shù)的末尾執(zhí)行代碼。

在QCoreApplication::exec()函數(shù)實現(xiàn)中的這幾行代碼:

if(threadData!=QThreadData::current()){
qWarning("%s:Mustbecalledfromthemainthread",self->metaObject()->className());
return-1;
}

引發(fā)出另一個有趣的知識點,那就是:在Qt多線程開發(fā)中,需要注意不要阻塞GUI線程,那么哪個是GUI線程呢?從上述源碼可以明確知道:QApplication a(argc, argv);所在線程就是GUI線程。

三、QThread::exec()

在多線程應用設計中,QThread::exec()用于為當前線程啟動一個新的事件循環(huán),為存在于該線程中的對象交付事件。在源碼中,QThread::exec()實現(xiàn)如下:

intQThread::exec()
{
Q_D(QThread);
QMutexLockerlocker(&d->mutex);
d->data->quitNow=false;
if(d->exited){
d->exited=false;
returnd->returnCode;
}
locker.unlock();
//創(chuàng)建QEventLoop事件循環(huán)。
QEventLoopeventLoop;
intreturnCode=eventLoop.exec();

locker.relock();
d->exited=false;
d->returnCode=-1;
returnreturnCode;
}

從源碼角度,也可見QThread::exec()實現(xiàn)中也調用到QEventLoop的exec()。

四、QEventLoop::exec()

QEventLoop::exec()用于進入主事件循環(huán)并等待直到exit()被調用。在調用該函數(shù)時需要傳入一個flags,如果指定了標志,則只處理標志允許的類型的事件,Qt中支持以下幾種標志:

序號 標志類型 描述
1 QEventLoop::AllEvents 所有事件
2 QEventLoop::ExcludeUserInputEvents 不處理用戶輸入事件,例如ButtonPress和KeyPress。
3 QEventLoop::ExcludeSocketNotifiers 不要處理套接字通知事件。
4 QEventLoop::WaitForMoreEvents 如果沒有可用的掛起事件,則等待事件。

注意,沒有被傳遞的事件不會被丟棄,這些事件將在下次傳入不過濾事件的標志調用procesvents()時被傳遞。

從源碼角度,QEventLoop::exec()實現(xiàn)如下:

intQEventLoop::exec(ProcessEventsFlagsflags)
{
Q_D(QEventLoop);
autothreadData=d->threadData.loadRelaxed();

//weneedtoprotectfromraceconditionwithQThread::exit
QMutexLockerlocker(&static_cast(QObjectPrivate::get(threadData->thread.loadAcquire()))->mutex);
if(threadData->quitNow)
return-1;

if(d->inExec){
qWarning("QEventLoop:instance%phasalreadycalledexec()",this);
return-1;
}

structLoopReference{
QEventLoopPrivate*d;
QMutexLocker&locker;

boolexceptionCaught;
LoopReference(QEventLoopPrivate*d,QMutexLocker&locker):d(d),locker(locker),exceptionCaught(true)
{
d->inExec=true;
d->exit.storeRelease(false);

autothreadData=d->threadData.loadRelaxed();
++threadData->loopLevel;
threadData->eventLoops.push(d->q_func());

locker.unlock();
}

~LoopReference()
{
if(exceptionCaught){
qWarning("Qthascaughtanexceptionthrownfromaneventhandler.Throwing
"
"exceptionsfromaneventhandlerisnotsupportedinQt.
"
"YoumustnotletanyexceptionwhatsoeverpropagatethroughQtcode.
"
"Ifthatisnotpossible,inQt5youmustatleastreimplement
"
"QCoreApplication::notify()andcatchallexceptionsthere.
");
}
locker.relock();
autothreadData=d->threadData.loadRelaxed();
QEventLoop*eventLoop=threadData->eventLoops.pop();
Q_ASSERT_X(eventLoop==d->q_func(),"QEventLoop::exec()","internalerror");
Q_UNUSED(eventLoop);//--releasewarning
d->inExec=false;
--threadData->loopLevel;
}
};
LoopReferenceref(d,locker);

//當進入一個新的事件循環(huán)時,刪除已發(fā)布的exit事件
QCoreApplication*app=QCoreApplication::instance();
if(app&&app->thread()==thread())
QCoreApplication::removePostedEvents(app,QEvent::Quit);

#ifdefQ_OS_WASM
//Partialsupportfornestedeventloops:MaketheruntimethrowaJavaSrcript
//exception,whichreturnscontroltothebrowserwhilepreservingtheC++stack.
//Eventprocessingthencontinuesasnormal.Thesleepcallbelowneverreturns.
//QTBUG-70185
if(threadData->loopLevel>1)
emscripten_sleep(1);
#endif

while(!d->exit.loadAcquire())
processEvents(flags|WaitForMoreEvents|EventLoopExec);

ref.exceptionCaught=false;
returnd->returnCode.loadRelaxed();
}

從上述源碼可知,QEventLoop::exec()本質會調用 processEvents()分發(fā)事件。 processEvents()實現(xiàn)如下:

cc77bc0a-bb5e-11ed-bfe3-dac502259ad0.png

從上圖所示代碼中,會調用QAbstractEventDispatcher::processEvents()實現(xiàn)事件分發(fā)。QAbstractEventDispatcher類提供了一個管理Qt事件隊列的接口,它從窗口系統(tǒng)和其他地方接收事件。然后它將這些事件發(fā)送到QCoreApplication或QApplication實例進行處理和交付。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 程序
    +關注

    關注

    115

    文章

    3743

    瀏覽量

    80661
  • 源碼
    +關注

    關注

    8

    文章

    629

    瀏覽量

    29074
  • 多線程
    +關注

    關注

    0

    文章

    276

    瀏覽量

    19878
  • 函數(shù)
    +關注

    關注

    3

    文章

    4256

    瀏覽量

    62223
  • Qt
    Qt
    +關注

    關注

    1

    文章

    300

    瀏覽量

    37731

原文標題:Qt這三個exec,傻傻分不清!

文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    proteussounder speaker buzzer 三個什么不同

    proteussounder speaker buzzer 三個什么不同,之前就發(fā)現(xiàn)了,但是一直很模糊,求助啊。。。。
    發(fā)表于 05-20 18:18

    labview如何實現(xiàn)三個事件互鎖?

    labview如何實現(xiàn)三個事件互鎖?即三個布爾量只允許一輸出為TRUE,剩下兩FALSE。有人能指點小弟一二嗎
    發(fā)表于 10-26 14:25

    Qt學習常用的類

    學的原因所在)。其實在QT你會發(fā)現(xiàn)有QApplication和return *.exec()是必須有的這也是QT運行時的機制, 當執(zhí)行到 *.ex
    發(fā)表于 10-18 09:47

    如何用C語言編寫圖上的三個方波的編程,能否解讀下三個方波之間聯(lián)系

    如何用C語言編寫圖上的三個方波的編程,能否解讀下三個方波之間聯(lián)系,老師給的方波,表示沒看懂,不知如何從何下手
    發(fā)表于 12-05 16:02

    請問這之間什么聯(lián)系

    工程師朋友,你好:我是新手,想問升壓型DC-DC芯片的開關電流Isw、輸出電流Iout和芯片的耗電,之間什么聯(lián)系?
    發(fā)表于 07-04 08:33

    如何鑒別可控硅的三個

    如何鑒別可控硅的三個極 鑒別可控硅三個極的方法很簡單,根據P-N結的原理,只要用萬用表測量一下三個之間的電阻值就可以。
    發(fā)表于 12-02 08:34 ?882次閱讀

    鑒別可控硅三個極的方法

    鑒別可控硅三個極的方法 鑒別可控硅三個極的方法很簡單,根據P-N結的原理,只要用萬用表測量一下三個之間的電
    發(fā)表于 01-14 16:20 ?1215次閱讀

    實施智能制造需要考慮三個支點

    筆者在《論智能制造》系列的“論智能制造的三個階段”,談到了對三個階段的基本認識。而如何實施智能制造,則需要考慮智能制造的三個支點:產品、
    發(fā)表于 11-06 15:31 ?892次閱讀

    閑聊HDMI、DVI、VGA三個接口的區(qū)別及聯(lián)系

    今天來聊聊一篇關于dvi接口:HDMI、DVI、VGA接口什么聯(lián)系的文章,現(xiàn)在就為大家來簡單介紹下dvi接口:HDMI、DVI、VGA接口什么聯(lián)系,希望對各位小伙伴們有所幫助。
    發(fā)表于 07-17 10:55 ?5265次閱讀

    談談PCBA、SMT、PCB之間區(qū)別與聯(lián)系

    很多剛開始接觸電子行業(yè)的人,常常會被PCBA、SMT、PCB這三個給弄混,很難分清楚它們之間的區(qū)別和聯(lián)系,接下來眾焱電子就通過通俗易懂的語言來談談PCBA、SMT、PCB
    的頭像 發(fā)表于 03-19 09:31 ?3w次閱讀

    Qt Designer、Qt Quick Designer和Qt Creator應用程序什么區(qū)別?

    Designer與之類似,只是用于構建QML GUI,而兩者都內置在Qt Creator。 我們通過使用它們的方法來解釋這些工具之間的區(qū)
    的頭像 發(fā)表于 03-17 09:40 ?7098次閱讀

    mosfet的三個電極怎么區(qū)分 mos管三個極電壓關系

    MOSFET(金屬氧化物半導體場效應晶體管)三個主要電極,分別是柵極(Gate)、漏極(Source)和源極(Drain)。這三個電極的區(qū)分方法如下
    的頭像 發(fā)表于 09-18 12:42 ?3.1w次閱讀

    docker exec命令的使用方法

    Docker是一種開源的容器化平臺,可以讓開發(fā)人員在容器打包和運行應用程序。它提供了一種快速、可靠和一致的方式來構建、部署和運行應用程序。Docker exec命令是Docker提供的一非常
    的頭像 發(fā)表于 11-23 09:33 ?1463次閱讀

    晶體管的三個極的電壓關系大小

    晶體管是一種半導體器件,用于放大電信號、開關電路和邏輯運算等。它是現(xiàn)代電子技術和計算機科學的核心之一。在晶體管,三個電極:基極、發(fā)射極和集電極。這三個電極的電壓
    的頭像 發(fā)表于 12-20 14:50 ?5303次閱讀

    微波測量的三個基本參量是什么

    微波測量是電子工程領域中的一重要分支,它涉及到對微波信號的頻率、幅度、相位等參數(shù)的測量。在微波測量,三個基本參量:頻率、幅度和相位。這三個
    的頭像 發(fā)表于 05-28 14:46 ?853次閱讀