ape*_*rez 10 c++ openmp reduction
我正在学习OpenMP,并遇到了以下示例:
#pragma omp parallel shared(n,a,b,c,d,sum) private(i)
{
#pragma omp for nowait
for (i=0; i<n; i++)
a[i] += b[i];
#pragma omp for nowait
for (i=0; i<n; i++)
c[i] += d[i];
#pragma omp barrier
#pragma omp for nowait reduction(+:sum)
for (i=0; i<n; i++)
sum += a[i] + c[i];
} /*-- End of parallel region --*/
Run Code Online (Sandbox Code Playgroud)
在最后一个for循环中,有一个nowait和一个reduction子句.它是否正确?减少条款不需要同步吗?
Kon*_*lph 18
nowait
第二个和最后一个循环中的s有些多余.OpenMP规范nowait
在该地区结束之前提到,所以也许这可以保留.
但是nowait
在第二个循环之前和它之后的显式屏障相互抵消了.
最后,关于shared
和private
条款.在你的代码中,shared
没有任何效果,private
根本就不应该使用:如果你需要一个线程私有变量,只需在并行区域内声明它.特别是,您应该声明循环变量内循环,而不是之前.
为了shared
有用,您需要告诉OpenMP默认情况下不应共享任何内容.您应该这样做以避免由于意外共享变量导致的错误.这是通过指定完成的default(none)
.这让我们:
#pragma omp parallel default(none) shared(n, a, b, c, d, sum)
{
#pragma omp for nowait
for (int i = 0; i < n; ++i)
a[i] += b[i];
#pragma omp for
for (int i = 0; i < n; ++i)
c[i] += d[i];
#pragma omp for nowait reduction(+:sum)
for (int i = 0; i < n; ++i)
sum += a[i] + c[i];
} // End of parallel region
Run Code Online (Sandbox Code Playgroud)
在某些方面,这似乎是一个家庭作业问题,我讨厌为人们做.另一方面,上面的答案并不完全准确,我觉得应该纠正.
首先,虽然在这个例子中不需要共享和私有条款,但我不同意Konrad不应该使用它们.人们并行化代码的最常见问题之一是他们没有花时间去理解变量的使用方式.不应该私有化和/或保护共享变量,这是我看到的最大数量的问题.通过检查如何使用变量并将它们放入适当的共享,私有等条款中,将大大减少您遇到的问题.
至于关于障碍的问题,第一个循环可以有一个nowait子句,因为在第二个循环中没有使用计算值(a).只有在计算值之前未使用计算值(c)时,第二个循环才能具有nowait子句(即,没有依赖性).在原始示例代码中,第二个循环上有一个nowait,但在第三个循环之前是一个显式屏障.这很好,因为你的教授试图显示使用显式屏障 - 尽管在第二个循环中忽略现在将使显式屏障变得多余(因为在循环结束时存在隐式屏障).
另一方面,可能根本不需要第二循环上的现在和显式屏障.在OpenMP V3.0规范之前,许多人认为某些事情是真的,但在规范中并未阐明.使用OpenMP V3.0规范,以下内容添加到2.5.1循环结构,表2-1调度子句类型值,静态(调度):
如果满足以下条件,静态调度的兼容实现必须确保在两个循环区域中将对线程使用相同的逻辑迭代次数分配:1)两个循环区域具有相同数量的循环迭代,2)两个循环区域具有相同的chunk_size值,或者两个循环区域都没有指定chunk_size,以及3)两个循环区域绑定到同一个并行区域.保证满足两个此类循环中相同逻辑迭代之间的数据依赖性,从而允许安全使用nowait子句(有关示例,请参见第170页的第A.9节).
现在在您的示例中,没有在任何循环上显示任何计划,因此这可能存在也可能不存在.原因是,默认计划是实现定义的,而大多数实现当前将默认计划定义为静态,但不保证这一点.如果你的教授在所有三个循环上都没有一个大小的静态程序类型,那么nowait可以用在第一个和第二个循环上,并且在第二个和第三个循环之间不需要任何障碍(隐式或显式)一点都不
现在我们进入第三个循环以及关于nowait和reduction的问题.正如Michy指出的那样,OpenMP规范允许指定(reduction和nowait).但是,完成还原不需要同步.在该示例中,可以使用nowait删除隐式屏障(在第三个循环的末尾).这是因为在遇到并行区域的隐式屏障之前没有使用减少(总和).
如果您查看OpenMP V3.0规范的2.9.3.6减少子句,您将找到以下内容:
如果未使用nowait,则减少计算将在构造结束时完成; 但是,如果还对应用了nowait的构造使用reduction子句,则对原始列表项的访问将创建一个种族,因此具有未指定的效果,除非同步确保它们在所有线程执行了所有迭代之后发生或部分构造,并且缩减计算已完成并存储该列表项的计算值.这可以通过屏障同步来最简单地确保.
这意味着如果您想在第三个循环之后在并行区域中使用sum变量,那么在使用它之前需要一个屏障(隐式或显式).如现在的例子,这是正确的.