首页 > 解决方案 > OpenMP 中数组内容的并行更新 - 并发添加元素

问题描述

我有以下代码,我想让它并行(伪代码)

int na = 10000000;
int nb = na;
double A[na];
double B[2*na];
double a;

for(int j=0;j<nb;j++)
{
  i = rand() % na;
  A[i]+=5.0*i;
  B[i+10]+=6.0*i*i;
}

当然,我不能使用#pragma omp parallel for,因为有时(无法预测)同一个元素会被两个线程同时访问。这段代码如何并行化?谢谢

标签: cparallel-processingopenmp

解决方案


有两种方法可以做到这一点:

  • 对值使用原子更新

    #pragma omp parallel for
    for(int j=0;j<nb;j++)
    {
        // make sure to declare i locally!
        int i = fun();
        #pragma omp atomic
        A[i]+=5.0*i;
    }
    

    这是最简单的方法。每次写入都是原子执行的,因此成本更高。您还需要考虑从多个线程访问相邻元素变得昂贵(错误共享)。如果A很大,并且每次更新都需要进行大量计算,请使用此选项。

  • 使用数组缩减

    #pragma omp parallel for reduction(+:A)
    for(int j=0;j<nb;j++)
    {
        // make sure to declare i locally!
        int i = fun();
        A[i]+=5.0*i;
    }
    

    这将为每个线程创建一个本地副本,该副本在并行区域之后A一起添加到外部。A这需要更多的内存和一些计算,但并行代码本身可以最有效地工作。如果A很小,并且每次更新的计算量很小,请使用此选项。

顺便说一句:永远不要rand()在并行应用程序中使用,它没有被定义为线程安全的,有时它是用锁实现的并且变得非常低效

编辑:在您的示例中,B您可以安全地应用omp atomicreduction单独应用到语句,因为每个操作只需要原子独立地执行。


推荐阅读