c++ - OpenMP:通过线程 ID 访问共享变量时是否需要临界区

标签 c++ multithreading openmp armadillo

我正在使用 OpenMP 并行化 for 循环。我正在尝试访问 C++ Armadillo vector by thread 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 vector 进行读/写?

最佳答案

您的代码没问题。重要的是要了解这一点

  • 在并行区域外声明的变量隐式共享
  • 在并行区域内声明的变量是隐式私有(private) - 因此每个线程都有它的本地拷贝。

所以为每个线程声明一个私有(private)的距离 vector 并不是很有用。您甚至不必拥有单独的 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 意味着每个线程都得到一个本地拷贝,在并行区域之后,reduction 操作应用于本地拷贝集。这是最简洁、惯用和性能最佳的解决方案。

附言使用 C++ 代码,有时会有点难以判断访问是否是尽管 operator[]arma::mat::row 在多线程程序中是安全的。您总是必须弄清楚您的代码是否意味着写入和/或读取共享数据。只有一个线程可以独占写入许多线程可以读取。

关于c++ - OpenMP:通过线程 ID 访问共享变量时是否需要临界区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45513385/

相关文章:

java - 在java中的线程之间来回发送对象?

c++ - 我的生产者消费者队列的任何明显问题或改进

c - 如何使用 OpenMP 将任务分配给单个线程?

c++ - 为什么 CPPUNIT_ASSERT_MESSAGE 会导致 OpenMP 出错?

c++ - 在类中使用 Armadillo 矩阵

java - Java/C++算法配置框架

c++ - 当我尝试在 C++ 中使用 SDL_RenderCopy 复制纹理时出现错误

c++ - 是否可以在另一个窗口中绘制(使用Opencv/ffmpeg

java - wait() 不强制线程等待?

linux - 如何强制单线程执行?