Qt QtConcurrent之 Run 函数用法
概述
Concurrent是并發(fā)的意思,QtConcurrent是一個(gè)命名空間,提供了一些高級(jí)的 API,使得在編寫多線程的時(shí)候,無需使用低級(jí)線程原語,如讀寫鎖,等待條件或信號(hào)。使用QtConcurrent編寫的程序會(huì)根據(jù)可用的處理器內(nèi)核數(shù)自動(dòng)調(diào)整使用的線程數(shù)。這意味著今后編寫的應(yīng)用程序?qū)⒃谖磥聿渴鹪诙嗪讼到y(tǒng)上時(shí)繼續(xù)擴(kuò)展。
而這里要講的是QtConcurrent::run函數(shù)的用法。
函數(shù)原型如下:
簡單的說,QtConcurrent::run()函數(shù)會(huì)在一個(gè)單獨(dú)的線程中執(zhí)行,并且該線程取自全局QThreadPool,該函數(shù)的返回值通過QFuture API提供。
請(qǐng)注意:該函數(shù)可能不會(huì)立即運(yùn)行; 函數(shù)只有在線程可用時(shí)才會(huì)運(yùn)行。
通過QtConcurrent::run()返回的QFuture不支持取消、暫停,返回的QFuture只能用于查詢函數(shù)的運(yùn)行/完成狀態(tài)和返回值。
導(dǎo)入模塊
在 C++ API changes 有關(guān)于 Qt Concurrent 的更改說明
Qt Concurrent has been moved from Qt Core to its own module大致意思就是,Qt Concurrent已經(jīng)從 QtCore 中移除并成為了一個(gè)獨(dú)立的模塊。
所以在使用的時(shí)候需要在工程文件中導(dǎo)入模塊,如下
示例
通過一個(gè)簡單的例子來看一下效果
#include "widget.h" #include <QDebug> #include <QThread> #include <QtConcurrent> #include <QFuture>Widget::Widget(QWidget *parent): QWidget(parent) {m_pBtn = new QPushButton("Click me",this);m_pBtn->setGeometry(100,100,220,70);connect(m_pBtn,&QPushButton::clicked,this,&Widget::onBtnClicked); }void func(QString str) {qDebug() << __FUNCTION__ << str << QThread::currentThreadId() << QThread::currentThread(); }void Widget::onBtnClicked() { #if 0QFuture<void> f1 =QtConcurrent::run(func,QString("aa"));f1.waitForFinished(); #elseQFuture < void > future = QtConcurrent::run([=](){qDebug() << __FUNCTION__ << QThread::currentThreadId() << QThread::currentThread();});QFuture < void > future2 = QtConcurrent::run([=](){qDebug() << __FUNCTION__ << QThread::currentThreadId() << QThread::currentThread();}); #endif }做了一個(gè)簡單的界面,通過點(diǎn)擊按鈕來調(diào)用 QtConCurrent::run函數(shù)。
這里在按鈕的槽函數(shù)中用了兩種方法來調(diào)用,一種是調(diào)用外部 extern 函數(shù),一種是使用了Lambda函數(shù),兩種方式只是寫法上的不同,結(jié)果都是一樣的。
注意:第一種方法調(diào)用外部函數(shù),如果該函數(shù)是類的成員函數(shù),會(huì)報(bào)以下錯(cuò)誤 : reference to no-static member function must be called…
如下圖:
定義外部函數(shù)
extern void func(QString str);這里運(yùn)行了第二種方法,Lambda函數(shù)來實(shí)現(xiàn)。
點(diǎn)擊按鈕后輸出以下結(jié)果:
連續(xù)調(diào)用兩次,分別在不同的線程中執(zhí)行的,這也就驗(yàn)證了該函數(shù)的作用。
問題來了
看到這兒,一定會(huì)有個(gè)疑問,上面說調(diào)用的函數(shù)必須是外部函數(shù),通過 extern 來定義函數(shù),那么,如果要調(diào)用類的成員函數(shù)怎么辦呢?先來看看 Qt 文檔的介紹。
使用成員函數(shù)
QtConcurrent :: run()也接受指向成員函數(shù)的指針。第一個(gè)參數(shù)必須是一個(gè)const引用或一個(gè)指向該類實(shí)例的指針。const成員函數(shù)一般傳遞 常量引用 (const reference),而非常量成員函數(shù)一般傳遞 指針 (pointer)
例如,在一個(gè)單獨(dú)的線程中調(diào)用QByteArray :: split()(一個(gè)const成員函數(shù))就像這樣完成:
// call 'QList<QByteArray> QByteArray::split(char sep) const' in a separate thread QByteArray bytearray = "hello world"; QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ','); ... QList<QByteArray> result = future.result();調(diào)用非const成員函數(shù)是這樣完成的:
// call 'void QImage::invertPixels(InvertMode mode)' in a separate thread QImage image = ...; QFuture<void> future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba); ... future.waitForFinished(); // At this point, the pixels in 'image' have been invertedOK,大概清楚了,我們修改一下上面的示例,讓 QtConCurrent::run去調(diào)用成員函數(shù)。
看代碼:
簡單說明一下,這里新增了一個(gè)成員函數(shù)myFunc,在槽函數(shù)onBtnClicked中進(jìn)行調(diào)用。
//調(diào)用類成員函數(shù)QFuture<void> f2 =QtConcurrent::run(this,&Widget::myFunc,QString("aaa"));使用Lambda函數(shù)
調(diào)用lambda函數(shù)是這樣完成的:
QFuture<void> future = QtConcurrent::run([=]() {// Code in this block will run in another thread }); ...上面示例中已經(jīng)添加了Lambda 函數(shù)的調(diào)用方法,如果說將要調(diào)用的函數(shù)執(zhí)行的內(nèi)容不多的話 可以考慮使用Lambda 函數(shù),使用會(huì)比較簡單。
參考資料:http://doc.qt.io/qt-5/qtconcurrentrun.html
總結(jié)
以上是生活随笔為你收集整理的Qt QtConcurrent之 Run 函数用法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt之创建并使用共享库
- 下一篇: Qt之Q_GLOBAL_STATIC创建