QtConcurrent::run()多線程的同步、異步

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 - 中文開源技術交流社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章