一、 QtConcurrent::run簡介
QtConcurrent
是Qt框架中的一個模塊,旨在提供方便且高效的並行編程實現方式。其中QtConcurrent::run
是使用最廣泛的方法。調用QtConcurrent::run
時,將會自動將函數以一個新的線程運行,並將函數返回結果傳遞迴主線程。
QtConcurrent::run
的用法簡單,僅需傳遞一個函數指針和函數參數,即可使用多線程的方式運行函數。使用QtConcurrent::run
可以充分利用多核處理器,提高程序效率,同時避免了使用底層多線程時的一些容易出現的線程安全問題。
二、 使用QtConcurrent::run進行多線程編程
我們來看一個簡單的例子,假設我們需要對一個字符串進行加密處理:
QString encrypt(QString str, int key) {
for(int i = 0; i < str.length(); ++i) {
str[i] = str[i] ^ key;
}
return str;
}
接下來,我們通過QtConcurrent::run
在新線程中運行這個函數:
QFuture future = QtConcurrent::run(encrypt, "hello world", 42);
使用QtConcurrent::run
時,它不會佔用主線程的時間,而是會自動啟用一個新的線程去執行函數,這個新的線程會在後台運行,直到函數執行完畢並返回結果。
在這裡我們用QFuture保存異步操作的結果,QFuture表示未來的結果,這個結果可以在需要的時候被獲取。
下面,我們通過QFuture
對象獲取異步操作的結果:
QString result = future.result();
在需要異步操作結果的地方使用future.result()
來獲取異步操作結果,如果異步操作沒有完成,future.result()
就會一直等待,直到異步操作完成為止。
三、使用QtConcurrent::run實現線程安全的容器操作
除了簡單的函數運算外,QtConcurrent::run
還可以用於執行容器的並行操作,比如在多線程中對QList
的修改操作。
在多線程中,對容器的修改操作需要考慮到線程安全,以避免出現競態條件等線程安全問題。一般的解決方法是添加互斥鎖,但互斥鎖會導致線程的等待與阻塞,降低程序的效率。
使用QtConcurrent::run
可以方便地實現線程安全的容器操作,使用QtConcurrent::run
時需要將需要並行執行的操作函數寫成可重入的函數。
以下是一個使用QtConcurrent::run
實現並行容器操作的例子,這裡我們實現一個在多線程中並行地對一個QList
進行排序的操作。
void sort(QList& list) {
std::sort(list.begin(), list.end());
}
void parallelSort(QList& list) {
QVector<QFuture> futures;
const int threadCount = QThread::idealThreadCount();
const int chunkSize = list.size() / threadCount;
int begin = 0, end = chunkSize;
for(int i = 0; i < threadCount; ++i) {
if(i == threadCount - 1) {
end = list.size();
}
futures.append(QtConcurrent::run(sort, list.mid(begin, end - begin)));
begin = end;
end += chunkSize;
}
for(int i = 0; i < futures.size(); ++i) {
futures[i].waitForFinished();
}
std::inplace_merge(list.begin(), list.begin() + chunkSize, list.end());
}
在parallelSort
函數中,我們將要排序的QList
按照QThread::idealThreadCount()
的數量進行分割,並將每個子序列交給一個新線程去執行排序操作。
執行完所有子線程後,我們使用std::inplace_merge
函數合併所有的排好序的子序列。
四、QtConcurrent::run的使用注意事項
雖然QtConcurrent::run
提供了一種方便且高效的多線程編程實現方式,但其也有其適用的範圍和使用注意事項:
- 線程池內的線程更加傾向於長期存在,不要把耗時很短的任務放進線程池中,可能會導致線程池耗費過多的系統資源,不利於程序性能。
// 不建議寫法 for (int i = 0; i < 100; ++i) { QtConcurrent::run([](){ /* do something */ }); }
QtConcurrent::run
會在新線程中自動執行函數,但也可以使用QThread
手動地創建新線程。QThread* thread1 = new QThread(); MyObject* object1 = new MyObject(); object1->moveToThread(thread1); QObject::connect(thread1, &QThread::started, object1, &MyObject::mySlot); thread1->start();
- 使用
QtConcurrent::run
時需要注意線程安全,避免並發操作數據時出現競爭問題。 QtConcurrent::run
可以將函數的返回結果傳遞到主線程,但是如果異步操作返回的結果需要馬上使用,應使用QFuture::result()
來等待異步操作的結束並獲取結果,否則可能會在異步操作沒結束前使用該結果。QString result = QtConcurrent::run(someFunction, params).result();
五、結語
QtConcurrent::run
是Qt框架中提供的一種方便、高效的多線程編程實現方式。使用QtConcurrent::run
可以避免使用底層多線程時的一些容易出現的線程安全問題,並充分利用多核處理器提高程序效率。
在使用QtConcurrent::run
時需要注意線程安全,合理地使用QThread
,避免將耗時很短的任務放進線程池中,正確地使用異步的結果等技巧,可以充分發揮QtConcurrent::run
的優勢。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/244091.html