一、導讀
本篇文章是關(guān)于Qt多線程應用設(shè)計方法的總結(jié),描述了Qt中進行多線程設(shè)計的四種方法,并列舉了常見應用場景下的多線程設(shè)計方案。合理選擇對應的方法來解決實際開發(fā)中遇到的問題有助于對應用程序進行更合理設(shè)計。
二、【方法一】 QThread:帶有可選事件循環(huán)的底層API
QThread是Qt中所有線程的基礎(chǔ),每個QThread實例代表和控制一個線程。使用QThread創(chuàng)建線程有兩種方法:
(1)直接實例化創(chuàng)建:提供了一個并行事件循環(huán),允許在輔助線程中調(diào)用QObject槽函數(shù)。
(2)子類化創(chuàng)建:繼承QThread,允許應用程序在啟動事件循環(huán)之前初始化新線程,或者在沒有事件循環(huán)的情況下運行并行代碼。
三、【方法二】 QThreadPool和QRunnable:重用線程
在實際開發(fā)中,頻繁創(chuàng)建和銷毀線程的代價可能會很高。為了減少這種開銷,可以對新任務重用現(xiàn)有的線程。QThreadPool是可重用QThread的集合。
要在QThreadPool的一個線程中運行代碼,需要重新實現(xiàn)QRunnable::run()并實例子類化的QRunnable。
使用````QThreadPool::start()將QRunnable放到QThreadPool的運行隊列中。當線程可用時,QRunnable::run()```中的代碼將在該線程中執(zhí)行。
【備注】:每個Qt應用程序都有一個全局線程池,可以通過QThreadPool::globalInstance()訪問這個線程池。這個全局線程池根據(jù)CPU中的核心數(shù)量會自動維護最佳的線程數(shù)量。但是在實際開發(fā)中,可以顯式創(chuàng)建和管理一個單獨的QThreadPool。
四、【方法三 】Qt并發(fā):使用高級API
Qt并發(fā)模塊提供了許多高級功能,用來處理一些常見的并行計算模式。例如:map、filter和reduce。Qt并發(fā)與使用QThread和QRunnable不同,這些函數(shù)不需要使用底層的線程原語,如互斥或信號量等。相反,它們返回的是一個QFuture對象,該對象可用于在準備線程或者線程完成時自動檢索函數(shù)的結(jié)果;QFuture還可以用來查詢、計算進度和暫停/恢復/取消計算。更方便的是,QFutureWatcher允許通過信號和槽函數(shù)與QFutures進行交互。
Qt Concurrent的并行計算模型:map、filter和reduce等算法會自動將計算負載分配到所有可用的處理器核心上,因此,我們今天編寫的應用程序,如果在以后部署到擁有更多處理器核心的系統(tǒng)上時將繼續(xù)得以擴展和使用,這一點非常方便。
Qt并發(fā)模塊還提供了QtConcurrent::run()函數(shù),它可以在另一個線程中運行任何函數(shù)。但是,QtConcurrent::run()只支持map、filter和reduce函數(shù)可用的特性子集,QFuture可用于檢索函數(shù)的返回值并檢查線程是否正在運行。
但是,對QtConcurrent::run()的調(diào)用只使用一個線程,不能暫停/恢復/取消,也不能查詢進程。
五、【方法四】 WorkerScript:QML中的線程化
WorkerScript QML類型允許JavaScript代碼與GUI線程并行運行。每個WorkerScript實例可以附加一個.js腳本。調(diào)用WorkerScript.sendMessage()時,腳本將在單獨的線程(和單獨的QML上下文)中運行。當腳本運行完成時,它可以將一個回復發(fā)送回GUI線程,該線程將調(diào)用WorkerScript.onMessage()信號處理程序。
使用WorkerScript類似于使用已移動到另一個線程的worker QObject,數(shù)據(jù)通過信號在線程之間進行傳輸。
【注】這種方法在QML中使用
六、如何選擇上述四種多線程設(shè)計方案
如上所示,Qt為開發(fā)多線程應用程序提供了幾種解決方案。而對于多線程應用程序的解決方案的選擇取決于:新線程的用途和線程的生存期。下面是Qt線程技術(shù)的一張比較表:
序號 | 特點 | QThread | QRunnable 和QThreadPool | QtConcurrent::run() | Qt Concurrent(Map/Filter/Reduce) | WorkerScript |
---|---|---|---|---|---|---|
1 | 開發(fā)語言 | C++ | C++ | C++ | C++ | QML |
2 | 是否可以指定線程優(yōu)先級 | 是 | 是 | |||
3 | 線程是否可以運行一個事件循環(huán) | 是 | ||||
4 | 線程是否可以通過信號接收數(shù)據(jù)更新 | 是(received by a worker QObject) | 是 (received by WorkerScript) | |||
5 | 線程是否可以使用信號來控制 | 是(received by QThread) | 是 (received by QFutureWatcher) | |||
6 | 線程是否可以通過QFuture來監(jiān)控 | 部分可以 | 是 | |||
7 | 是否擁有內(nèi)置能力:取消/暫停/恢復 | 是 | ||||
七、Qt多線程應用設(shè)計方案
在本小節(jié)中,列出了Qt中常見的幾種多線程應用的設(shè)計方案,如下表所示:
線程生命周期 | 應用場景 | 解決方案 |
---|---|---|
一次調(diào)用 | 在另一個線程中運行一個新的線程函數(shù),可以選擇在運行期間進行進度更新。 | Qt提供了不同的解決方案: 1、 將該函數(shù)放在QThread::run()的重新實現(xiàn)中,并啟動QThread,發(fā)出信號更新進度。 2、該函數(shù)放在QRunnable::run()的重新實現(xiàn)中,并將QRunnable添加到QThreadPool中,寫入線程安全的變量更新進度。 3、使用QtConcurrent:: Run()運行函數(shù),寫入線程安全的變量更新進度。 |
一次調(diào)用 | 在另一個線程中運行一個現(xiàn)有函數(shù)并獲取它的返回值。 | 使用QtConcurrent:: Run()運行函數(shù),讓QFutureWatcher在函數(shù)返回時發(fā)出finished()信號,并調(diào)用QFutureWatcher::result()來獲取函數(shù)的返回值。 |
一次調(diào)用 | 使用所有可用的硬件資源對容器(Container)的所有項執(zhí)行操作。例如:從圖像列表生成縮略圖。 | 使用QtConcurrent的QtConcurrent::filter()函數(shù)來選擇容器元素,使用QtConcurrent::map()函數(shù)來為每個元素關(guān)聯(lián)一個操作。 |
一次調(diào)用/永久存在 | 在純QML應用程序中完成長時間的計算,并在結(jié)果準備好時更新GUI。 | 將計算代碼放在.js腳本中,并將其附加到WorkerScript實例。調(diào)用WorkerScript.sendMessage()在新線程中啟動計算。讓腳本也調(diào)用sendMessage(),將結(jié)果傳遞回GUI線程。在onMessage中處理結(jié)果并更新GUI。 |
永久存在 | 在另一個線程中有一個對象,它可以根據(jù)請求執(zhí)行不同的任務,并且可以接收、處理新的數(shù)據(jù)。 | 子類化一個QObject來創(chuàng)建一個worker,實例化這個worker對象和一個QThread,將worker移動到新線程,通過排隊的信號和槽函數(shù)連接向worker對象發(fā)送命令或數(shù)據(jù)。 |
永久存在 | 在另一個線程中重復執(zhí)行開銷較大的操作,其中該線程不需要接收任何信號或事件。 | 直接在QThread::run()的重新實現(xiàn)中寫入無限循環(huán),在沒有事件循環(huán)的情況下啟動線程,讓線程發(fā)出信號將數(shù)據(jù)發(fā)送回GUI線程。 |
審核編輯:劉清
-
cpu
+關(guān)注
關(guān)注
68文章
11063瀏覽量
216478 -
信號處理
+關(guān)注
關(guān)注
48文章
1055瀏覽量
104000 -
GUI
+關(guān)注
關(guān)注
3文章
677瀏覽量
40990
原文標題:這四種使用Qt多線程設(shè)計的“姿勢”...
文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
Linux下多線程編程總結(jié)
基于TCP/IP協(xié)議的多線程通信的基本方法
QNX環(huán)境下多線程編程
多線程技術(shù)在串口通信中的應用
設(shè)計多線程和多核系統(tǒng)

關(guān)于多線程編程教程及經(jīng)典應用案例的匯總分析
多線程好還是單線程好?單線程和多線程的區(qū)別 優(yōu)缺點分析
什么是多線程編程?多線程編程基礎(chǔ)知識
關(guān)于Linux下多線程編程技術(shù)學習總結(jié)

RT-Thread學習筆記 --(6)RT-Thread線程間通信學習過程總結(jié)

基于QT自制上位機(多線程)

關(guān)于Python多進程和多線程詳解

評論