2 回答

TA貢獻2051條經驗 獲得超10個贊
您鏈接的問題是在“多個線程寫入單個容器的情況下,STL向量容器不是線程安全的”這一事實。如果您調用可能導致重新分配std::vector
持有的基礎數組的方法,那么這只是正確的說法。push_back()
,pop_back()
并且insert()
是這些危險方法的例子。
如果您需要線程安全重新分配,那么庫intel線程構建塊為您提供并發向量容器。您不應該在單線程程序中使用tbb :: concurrent_vector,因為訪問隨機元素所花費的時間高于std :: vector執行相同操作所需的時間(即O(1))。然而,并發矢量電話push_back()
,pop_back()
,insert()
在一個線程安全的方式,甚至當再分配發生。
編輯1:以下英特爾演示文稿的幻燈片46和47 給出了使用tbb :: concurrent_vector并發重新分配的說明性示例
編輯2:順便說一句,如果你開始使用英特爾Tread Building Block(它是開源的,它適用于大多數編譯器,它與C ++ / C ++ 11功能集成得比openmp好得多),那么你不需要使用openmp創建parallel_for,這是使用tbb的parallel_for的一個很好的例子。

TA貢獻1874條經驗 獲得超12個贊
我認為你可以std::vector
在大多數時間使用OpenMP并且仍然具有良好的性能。例如,以下代碼std::vectors
并行填充,然后將它們組合在一起。只要您的主循環/填充功能是瓶頸,這通??梢院芎玫毓ぷ鞑⑶沂蔷€程安全的。
std::vector<int> vec;#pragma omp parallel{ std::vector<int> vec_private; #pragma omp for nowait //fill vec_private in parallel for(int i=0; i<100; i++) { vec_private.push_back(i); } #pragma omp critical vec.insert(vec.end(), vec_private.begin(), vec_private.end());}
編輯:
OpenMP 4.0允許使用用戶定義的縮減#pragma omp declare reduction
。上面的代碼可以簡化為
#pragma omp declare reduction (merge : std::vector<int> : omp_out.insert(omp_out.end(), omp_in.begin(), omp_in.end()))std::vector<int> vec;#pragma omp parallel for reduction(merge: vec)for(int i=0; i<100; i++) vec.push_back(i);
編輯:到目前為止我所顯示的內容并沒有按順序填充向量。如果訂單很重要,那么這可以這樣做
std::vector<int> vec;#pragma omp parallel{ std::vector<int> vec_private; #pragma omp for nowait schedule(static) for(int i=0; i<N; i++) { vec_private.push_back(i); } #pragma omp for schedule(static) ordered for(int i=0; i<omp_get_num_threads(); i++) { #pragma omp ordered vec.insert(vec.end(), vec_private.begin(), vec_private.end()); }}
這樣可以避免為每個線程保存std :: vector,然后將它們串行合并到并行區域之外。我在這里了解了這個“技巧” 。對于用戶定義的縮減,我不確定如何做到這一點(或者甚至可能)。。用戶定義的縮減不可能做到這一點。
我剛剛意識到關鍵部分是不必要的,我從這個問題中找到了parallel-cumulative-prefix-sums-in-openmp-communic-values-between-thread。此方法也可以使訂單正確
std::vector<int> vec;size_t *prefix;#pragma omp parallel{ int ithread = omp_get_thread_num(); int nthreads = omp_get_num_threads(); #pragma omp single { prefix = new size_t[nthreads+1]; prefix[0] = 0; } std::vector<int> vec_private; #pragma omp for schedule(static) nowait for(int i=0; i<100; i++) { vec_private.push_back(i); } prefix[ithread+1] = vec_private.size(); #pragma omp barrier #pragma omp single { for(int i=1; i<(nthreads+1); i++) prefix[i] += prefix[i-1]; vec.resize(vec.size() + prefix[nthreads]); } std::copy(vec_private.begin(), vec_private.end(), vec.begin() + prefix[ithread]);}delete[] prefix;
- 2 回答
- 0 關注
- 1422 瀏覽
添加回答
舉報