0

我在理解 OpenMP 如何与嵌套循环一起工作时遇到问题。请帮忙!

我得到以下代码并行运行:

#pragma omp parallel private(i)
{
for(i=0; i<n; i++)
{
    #pragma omp for
    for(j=0; j<n; j++)
    {
        if(asubsref(seed,j) > 0)
            asubsref(bin,j) = asubsref(bin,j) + 1;
    }
    #pragma omp for
    for(j=0; j<n; j++)
        asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}
}

但是,我不太确定这段代码是如何工作的(我只是运气好)。这就是我认为它正在做的事情......

所以for(i=0; i<n; i++)被分成不同的线程并并行运行。因为i被声明为private,所以循环的每个实例都是“沙盒”的;也就是说,任何更改都j保留在该线程中(至少在所有线程完成之前?)。我很困惑,因为不声明#pragma omp for会导致代码中断......我不确定为什么会这样。

如果有人可以指导我完成这段代码的工作,我将非常感激!谢谢!

4

1 回答 1

2

这是一个典型的做法,以减少多个进入和存在于并行区域的开销。将您问题中的代码与以下等效代码进行比较:

for (i=0; i<n; i++)
{
    #pragma omp parallel for
    for (j=0; j<n; j++)
    {
        if (asubsref(seed,j) > 0)
            asubsref(bin,j) = asubsref(bin,j) + 1;
    }
    #pragma omp parallel for
    for (j=0; j<n; j++)
        asubsref(seed,j) = asubsref(seed,j) - asubsref(w,i);
}

它随着时间的推移运行外循环i n。在外循环的每次迭代中,它运行两个并行循环,在线程之间j拆分迭代。n这里的问题是你里面有两个平行的区域,每个区域都是激活的n时间。这可能会为某个值的间隔增加显着的开销n(实际间隔将取决于许多因素)。

为了减少开销,将整个代码放在一个并行区域内。因此,每个线程将执行外部循环的所有迭代,而内部迭代仍将在线程之间拆分。如果您删除工作共享结构,则内部循环将不会分布在线程之间。相反,每个线程都将执行外部内部迭代的全部范围,因此例如asubsref(bin,j)会增加最num_threads多次而不是一次(为什么“最多”?提示:不受保护的并发数据访问)。

大多数时候,当一个人在并行结构中运行一个外循环时,人们希望不同的线程在相同的迭代中保持滴答作响。这可以通过循环体末尾的屏障来实现:

#pragma omp parallel private(i)
{
    for (i = 0; i < n; i++)
    {
        ...
        #pragma omp barrier
    }
}

在您的情况下,不需要显式障碍,因为for工作共享构造在其末端有一个隐式障碍。

于 2012-11-27T09:53:27.057 回答