C++ Parallel STL


考慮一個算法,代碼如下:

#include <algorithm>

void process(int& x){
    //do some calculate
}

int main()
{
    int arr[100000];
    std::for_each( arr, arr+100000, [](auto & x){ process(x); });
}

for_each對於每一個數組arr的成員,都去調用了process(int& x)。這個過程是單線程(main所在的主線程)進行的。

如果想增加性能,讓多線程並行的處理,需要做一些改造。例如,創建線程1處理0-30000項,創建線程2處理30001-60000項,主線程處理剩余項。

在C++17中,可以請求算法庫做並行處理。怎么請求呢?代碼如下:

#include <execution>
//...
int main(){
    int arr[100000];
    std::for_each( std::execution::par, arr, arr+10000, [](auto & x){ process(x); });
}

新的重載函數多出了個指定策略的參數std::execution::par。這個參數意味着算法庫可能會偷偷的創建后台線程輔助完成for_each算法。

另外還有std::execution::seq,和std::execution::par_unseq。這些都是算法庫預定義的常量。

因為標准庫算法都會涉及到對容器和元素的讀寫操作,在多線程條件下,就會有數據競爭問題。數據競爭的解決,是庫的用戶責任。這意味着有時候就需要用互斥量,內存模型等機制保護數據的完整性。

例如:下面這段代碼,程序可能要掛掉了。在多線程環境下,對共享的資源v的插入會出現不可預知的錯誤。

int a[] = {0,1,3,4,5,6,7,8,9};
std::vector<int> v;
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) {
  v.push_back(i*2+1); // 錯誤:數據競爭
});

最直接的解決方式,加鎖保護,代碼如下:

int a[] = {0,1,3,4,5,6,7,8,9};

std::vector<int> v;
std::mutex m;

std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) {
  std::lock_guard<std::mutex> guard(m);  //互斥量保護v
  v.push_back(i*2+1); 
});
  

有三種並行策略,各個含義如下:

std::execution::seq
調用者線程單線程方式,以不確定的順序訪問元素
std::execution::par
多線程(由庫隱式的創建線程)方式,在每個線程中,以不確定的順序訪問元素
std::execution::par_unseq
multiple threads and may be vectorized - calls are unsequenced with respect to each other and possibly interleaved

我完全沒懂,需要再研究。什么是“不確定順序的“(indeterminately sequenced)?什么是“向量化的”(vectorized)?什么是交互的“interleaved”?都是什么鬼?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM