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