QT消息/事件循环机制与多线程的关系
關(guān)于Qt子線程和消息循環(huán)
一、QT消息/事件循環(huán)機(jī)制
Qt作為一個(gè)可視化GUI界面操作系統(tǒng),是基于事件驅(qū)動(dòng)的,我們程序執(zhí)行的順序不再是線性,而是由一個(gè)個(gè)應(yīng)用程序內(nèi)部或外部的事件進(jìn)行驅(qū)動(dòng),無事件時(shí)便阻塞。這個(gè)循環(huán)概念類似于while的函數(shù)循環(huán),函數(shù)體內(nèi)不斷處理用戶的輸入,類比到事件循環(huán)中,用戶點(diǎn)擊了鼠標(biāo)、按下了鍵盤,便被稱作為事件。
一般對于帶UI窗口的程序來說,“事件”是由操作系統(tǒng)或程序框架在不同的時(shí)刻發(fā)出的。當(dāng)用戶按下鼠標(biāo)、敲下鍵盤,或者是窗口需要重新繪制的時(shí)候,計(jì)時(shí)器觸發(fā)的時(shí)候,都會(huì)發(fā)出一個(gè)相應(yīng)的事件。我們把“事件循環(huán)”的代碼 提煉/抽象 如下
function eventloop() {
? ? initialize();
? ? bool shouldQuit = false;
? ? while(false == shouldQuit)
? ? {
? ? ? ? var message = get_next_message();
? ? ? ? process_message(message);
? ? ? ? if (message == QUIT)?
? ? ? ? {
? ? ? ? ? ? shouldQuit = true;
? ? ? ? }
? ? }
}
?
機(jī)制解釋
這樣的程序運(yùn)行流程,我們叫做“事件驅(qū)動(dòng)”式的程序。一般的Qt程序,main函數(shù)中都有一個(gè)QCoreApplication/QGuiApplication/QApplication,并在末尾調(diào)用 exec。Application中的這個(gè)EventLoop,我們稱作“主事件循環(huán)”,所有的事件分發(fā)、事件處理都從這里開始。Application還提供了sendEvent和poseEvent兩個(gè)函數(shù),分別用來發(fā)送事件。sendEvent發(fā)出的事件會(huì)立即被處理,也就是“同步”執(zhí)行。postEvent發(fā)送的事件會(huì)被加入事件隊(duì)列,在下一輪事件循環(huán)時(shí)才處理,也就是“異步”執(zhí)行。
函數(shù)阻塞
我們常常使用Qt來編寫UI界面,這樣確實(shí)很方便,但是Qt的事件循環(huán)機(jī)制在這里會(huì)出現(xiàn)一些問題。舉兩個(gè)例子:
?
比如說:假設(shè)我們有一個(gè)鼠標(biāo)點(diǎn)擊事件,事件循環(huán)會(huì)分發(fā)出這個(gè)鼠標(biāo)點(diǎn)擊事件,調(diào)用特定的鼠標(biāo)事件處理函數(shù),但是這個(gè)信號卻做了很多耗時(shí)的事情,于是便堵塞著、等待著事件處理函數(shù)返回,這是堵塞了時(shí)間循環(huán),它意味著沒有消息被分發(fā)了,再次有事件或消息時(shí)無法被及時(shí)分發(fā)處理,直到我們從槽函數(shù)返回了,然后才能繼續(xù)處理掛起的消息。
再比如說:我們有時(shí)候又需要做一些復(fù)雜的計(jì)算,這段計(jì)算程序就在我們的UI界面的事件循環(huán)中,這些計(jì)算的耗時(shí)甚至達(dá)到了幾秒鐘,在沒有計(jì)算完成之前,函數(shù)不會(huì)退出(相當(dāng)于阻塞),事件循環(huán)得不到及時(shí)處理,就會(huì)發(fā)生UI卡住的現(xiàn)象。
多線程使用
以上兩種情況,在消息循環(huán)被卡住的情況下,widgets將不能更新它們自身,不可能有更多的互動(dòng),timers將不會(huì)被激發(fā),網(wǎng)絡(luò)通訊將緩慢下來,或者停止。進(jìn)一步的說,許多窗口管理器將檢測到你的應(yīng)用程序不在處理事件了, 然后告訴用戶你的程序沒有響應(yīng)。這就是為什么快速的對事件響應(yīng)并且即時(shí)返回到事件循環(huán)是多么的重要。
對于上述兩種情況,假如我們有一個(gè)很長的任務(wù)去運(yùn)行但是又不希望堵塞這個(gè)消息循環(huán),該怎么做呢?可行的方法如下:
將這個(gè)任務(wù)移到另一個(gè)線程中,
我們也能手動(dòng)強(qiáng)制事件循環(huán)去運(yùn)行,這個(gè)方法是通過在堵塞的任務(wù)函數(shù)中調(diào)用QCoreApplication::processEvent()來實(shí)現(xiàn),QCoreApplication::processEvent()將處理所有在消息隊(duì)列中的消息并返回給調(diào)用者。
另一個(gè)可選的選項(xiàng)是我們能夠強(qiáng)制重入事件循環(huán)的對象,就是QEventLoop類。通過調(diào)用QEventLoop::exec()我們將重入事件循環(huán),然后我們能將槽函數(shù)QVentLoop::quit()連接到信號上去使它退出。
其中最常用的是創(chuàng)建子線程的辦法
?
總結(jié)
以上是生活随笔為你收集整理的QT消息/事件循环机制与多线程的关系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决: bash: unzip: com
- 下一篇: QT的事件分发、事件过滤器详解