Qt 提供了 QtConcurrent 模塊,處理一些常見的並行計算,最大的特點就是無需再使用互斥鎖這種很低級的操作,全都封裝好了。除此以外,QFuture、QFutureWatcher、QFutureSynchronizer 類提供了一些輔助性的操作。參考:Qt 中的多線程技術 - 知乎 (zhihu.com)
【QtConcurrent::run() 需注意】
- 默認扔進了全局線程池,即 QThreadPool::globalInstance()
- 傳參數的時候,都會複製一份副本。即使參數是引用,在函數中修改數據也不會對源對象產生任何影響。
- QFuture::result() 與 QFuture::waitForFinished()函數都會阻塞,直到結果可用才繼續之後的代碼。
- QtConcurrent::run()返回的QFuture不支持取消、暫停和進度報告。返回的QFuture只能用於查詢運行/完成狀態和函數的返回值。
可以執行無參、含參、有返回值函數,以及lambda表達式。參考Qt多線程編程之高級函數 - 知乎 (zhihu.com) 和 Qt 多線程的幾種實現方式 - 知乎 (zhihu.com)
函數原型:
QFuture<T> QtConcurrent::run(Function function, ...)
QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...)
默認全局線程池。
【QFutureWatcher】
QFuture::result() 會阻塞,若不想一直等待結果,可以使用QFutureWatcher獲取通知。
參考 QT高級線程API總結(一)QtConcrrent::run_qtconcurrent::run(qthreadpool::globalinstance(), [-CSDN博客
QByteArray bytearray = "hello ,world"; QFuture<QString > future = QtConcurrent::run(this, &MainWindow::threadFunc, bytearray); //QFutureWatcher<QString> *m_watcher = new QFutureWatcher<QString>(this); m_watcher = new QFutureWatcher<QString>(this); m_watcher->setFuture(future); connect(m_watcher, &QFutureWatcher<QString>::finished, [=](){ qDebug() << "finished"; }); QString MainWindow::threadFunc(QByteArray &arg){ qDebug() << "threadFunc:" << arg; //do process... return QString(""); };
【QFutureSynchronizer】
爲了簡化多個QFuture的同步等待操作,特地爲我們提供了一個模板類QFutureSynchronizer。
參考 使用QFuture類監控異步計算的結果 - findumars - 博客園 (cnblogs.com)
#include <QCoreApplication> #include <QFuture> #include <QFutureSynchronizer> #include <QtConcurrent> #include <QDebug> //計算第lindex 個 斐波那契數值 qulonglong Fibonacci(int index) { qulonglong f1 = 1, f2 = 1, cur = 0; for(int i = 3; i <= index; i++) { cur = f1 + f2; f1 = f2; f2 = cur; } return cur; } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QFutureSynchronizer<qulonglong> synchronizer; synchronizer.addFuture(QtConcurrent::run(Fibonacci, 50)); synchronizer.addFuture(QtConcurrent::run(Fibonacci, 100)); synchronizer.waitForFinished(); qDebug() << "第50個斐波那契數: " << synchronizer.futures()[0].result(); qDebug() << "第100個斐波那契數: " << synchronizer.futures()[1].result(); return a.exec(); }
【QThreadPool】
常用API如下:
/ 獲取和設置線程中的最大線程個數 int maxThreadCount() const; void setMaxThreadCount(int maxThreadCount); // 給線程池添加任務, 任務是一個 QRunnable 類型的對象 // 如果線程池中沒有空閒的線程了, 任務會放到任務隊列中, 等待線程處理 void QThreadPool::start(QRunnable * runnable, int priority = 0); // 如果線程池中沒有空閒的線程了, 直接返回值, 任務添加失敗, 任務不會添加到任務隊列中 bool QThreadPool::tryStart(QRunnable * runnable); // 線程池中被激活的線程的個數(正在工作的線程個數) int QThreadPool::activeThreadCount() const; // 嘗試性的將某一個任務從線程池的任務隊列中刪除, 如果任務已經開始執行就無法刪除了 bool QThreadPool::tryTake(QRunnable *runnable); // 將線程池中的任務隊列裏邊沒有開始處理的所有任務刪除, 如果已經開始處理了就無法通過該函數刪除了 void QThreadPool::clear(); // 在每個Qt應用程序中都有一個全局的線程池對象, 通過這個函數直接訪問這個對象 static QThreadPool * QThreadPool::globalInstance();
參考 QT從入門到入土(五(2))——多線程(QtConcurrent::run())和線程池 轉載 - 太空堡壘 - OSCHINA - 中文開源技術交流社區