2017-08-04 37 views
2

我正在使用OpenMP來並行化for循環。我試圖通過線程ID訪問C++ Armadillo向量,但是我想知道是否必須將訪問放在關鍵部分,即使不同線程訪問不相交區域的內存。 這是我的代碼:OpenMP:當我通過線程ID訪問共享變量時是否需要臨界區域

#include <armadillo> 
#include <omp.h> 
#include <iostream> 

int main() 
{ 

     arma::mat A = arma::randu<arma::mat>(1000,700); 
     arma::rowvec point = A.row(0); 
     arma::vec distances = arma::zeros(omp_get_max_threads()); 

     #pragma omp parallel shared(A,point,distances) 
     { 

       arma::vec local_distances = arma::zeros(omp_get_num_threads()); 
       int thread_id = omp_get_thread_num(); 

       for(unsigned int l = 0; l < A.n_rows; l++){ 
         double temp = arma::norm(A.row(l) - point,2); 
         if(temp > local_distances[thread_id]) 
           local_distances[thread_id] = temp; 
       } 

       // Is it necessary to put a critical section here? 
       #pragma omp critical 
       if(local_distances[thread_id] > distances[thread_id]){ 
         distances[thread_id] = local_distances[thread_id]; 
       } 

     } 

     std::cout << distances[distances.index_max()] << std::endl; 

} 

是否有必要把讀/在我的情況寫入distances載體?

+1

不,這不應該要求關鍵部分。 – subzero

回答

2

多線程的困難來自需要處理共享可變狀態。一個線程訪問可變(可更改)數據或許多線程同時訪問不可變(常量)數據沒有任何問題。只有當多個線程需要訪問相同的可變數據時,同步/關鍵部分纔是必需的。

您的代碼屬於第一種情況,因爲每個thread_id索引唯一數據 - 一次只有一個線程更改數據。

2

你的代碼沒問題。理解這一點很重要

  • 聲明在並行區域之外的變量隱含地爲shared
  • 在並行區域內聲明的變量隱含地爲private - 因此每個線程都有其本地副本。

因此,爲每個線程聲明距離的私有向量並不是很有用。您甚至不必單獨使用local_distances,因爲訪問distances是正確的。 (雖然應該注意,對distances的訪問效率非常低,因爲不同的線程會嘗試在同一個緩存行上寫入數據)。無論如何,整個事情被稱爲減少,OpenMP對此有輕鬆的支持。您可以編寫類似如下:

arma::mat A = arma::randu<arma::mat>(1000,700); 
arma::rowvec point = A.row(0); 
double distance = 0.; 
#pragma omp parallel reduction(max:distance) 
{ 
     for(unsigned int l = 0; l < A.n_rows; l++){ 
       distance = std::max(distance, arma::norm(A.row(l) - point,2)); 
     } 
} 
std::cout << distance << std::endl; 

聲明一個變量reduction意味着每個線程都有一個本地副本,並在並行區域後,減少操作應用到集本地副本。這是最簡潔,慣用和性能最佳的解決方案。

P.S.使用C++代碼,有時可能難以確定是否訪問例如儘管operator[]arma::mat::row在多線程程序中是安全的。您始終必須弄清楚您的代碼是否意味着寫入和/或從共享數據讀取。只有一個線程可能獨佔地編寫許多線程可能會讀取。

+0

謝謝!實際上我不得不修改我的代碼,以便能夠獲得具有最大距離的'A'中的行的索引。所以我不僅需要最大距離,而且還需要該行的索引。我應該更新我的問題還是發表另一篇文章?但我不確定減少變量是否可以處理類似的事情。 – Cauchy

+0

儘管最大縮減和lastprivate(使用C,而不是C++)組合通常效果更好,但用戶定義的縮減通常主張max元素。 – tim18

+0

看看[這個答案](https://stackoverflow.com/a/42771196/620382),看看如何用OpenMP用戶定義的縮減來完成argmax。 – Zulan

相關問題