Openmp中循环内部的关键部分

时间:2016-11-03 18:34:16

标签: multithreading openmp critical-section

我有以下代码:

#pragma omp parallel for private(dist,i,j)
for(k=0;k<K;k++)
{
 //some code 
 for(i=0;i<N;i++)
    {
      #pragma omp critical
       {
        if(min_dist[i]>dist[i])//The point i belongs to the cluster k
        {
         newmembership[i]=k;
         min_dist[i]=dist[i];
        }
       }
    dist[i]=0;
    }
}

dist是一个私有变量,而newmemebership和min_dist是一个共享变量。对于我的测试用例,如果我们运行代码而不添加关键部分构造,代码仍然有效。据我所知,它不应该作为两个线程可能正在运行i的相同值,并可能修改导致冲突的min_dist [i]和newmembership [i]。

请解释是否有必要添加关键部分构造,还有更好的方法来实现上述即使用锁或信号量吗?

1 个答案:

答案 0 :(得分:3)

删除critical部分将是一场数据竞赛。请考虑以下执行:

(min_dist[42] == 100)
time | Thread 0                       | Thread 1
----------------------------------------------------------------------
  0  | k = 13                         | 
  1  | i = 42                         | k = 14
  2  | dist[i] = 50                   | i = 42
  3  | min_dist[i] > dist[i] ==> true | dist[i] = 75
  4  | newmembership[i] = 13          | min_dist[i] > dist[i] ==> true
  5  | min_dist[i]=50                 | newmembership[i] = 14
  6  | ...                            | min_dist[i]=75

所以你最终得到了一个非最小的解决方案。您最终可能会遇到有冲突的min_dist / newmembership值。

另一种方法是创建线程private local_min_dist / local_newmembership数组,并在执行结束时合并它们:

#pragma omp parallel
{
    // Note: implicitly private because defined inside the parallel region
    int local_newmembership[N];
    int local_min_dist[N];

    #pragma omp for private(dist,i,j)
    for(k=0;k<K;k++)
    {
        //some code 
        for(i=0;i<N;i++)
        {
            // NOTE: No critical region necessary
            // as we operate on private variables
            if(local_min_dist[i]>dist[i])//The point i belongs to the cluster k
            {
                local_newmembership[i]=k;
                local_min_dist[i]=dist[i];
            }
            dist[i]=0;
        }
    }

    for (i = 0; i < N; i++)
    {
        // Here we have a critical region,
        // but it is outside of the k-loop
        #pragma omp critical
        if (min_dist[i] > local_min_dist[i])
        {
            newmembership[i] = local_newmembership[i];
            local_min_dist[i] = local_min_dist[i];
        }
    }
}