看一下文档here,以下结构得到了很好的定义:
#pragma omp parallel //Line 1
{
#pragma omp for nowait //Line 3
for (i=0; i<N; i++)
a[i] = // some expression
#pragma omp for //Line 6
for (i=0; i<N; i++)
b[i] = ...... a[i] ......
}
自
在这里,nowait子句意味着线程可以在第二个循环中启动,而其他线程仍在第一个循环中工作。由于两个循环在此处使用相同的计划,因此使用a [i]的迭代确实可以依靠它来计算该值。
我很难理解为什么会这样。假设Line 3
是:
#pragma omp for
然后,由于在Line 6
之前有一个隐式屏障,因此下一个for循环将在a
的所有索引处都具有完全计算的值。但是,使用no wait
中的Line 3
,它如何工作?
假设Line 1
触发4个线程,t1, t2, t3
和t4
。假设N
为8,则第一个for循环中的索引分区为:
t1: 0, 4
t2: 1, 5
t3: 2, 6
t4: 3, 7
假设t1
首先完成索引0
和4
,然后降落到Line 6
,现在到底发生了什么?如何保证它现在可以在相同的索引0
和4
上运行,而它们在上一次迭代中已正确计算出a
的值?如果第二个for
循环访问a[i+1]
怎么办?
答案 0 :(得分:7)
您引用的材料是错误的。如果在两个循环中都添加schedule(static)
,这将变得正确-这样可以保证连续循环的线程之间的索引分配相同。默认计划是由实现定义的,您不能假定它为static
。引用标准:
时间表和迭代次数相同的不同循环区域, 即使它们出现在同一平行区域,也可以分布 线程之间的迭代方式有所不同。唯一的例外是 静态时间表,如表2.5所示。依赖的程序 哪个线程在其他任何线程下执行特定的迭代 情况不合格。
如果第二个for循环访问a[i+1]
,则必须将障碍完全留在那儿。
答案 1 :(得分:2)
对我来说,示例中没有潜在问题的说法是错误的。
实际上,调度将与未明确定义的调度相同。这将是默认值。此外,如果调度是a
类型的,那么实际上不会有任何问题,因为在第二个循环内处理数组static
中任何给定数据的线程将与第二个循环中的相同。一个会在第一个循环中编写的代码。
但是这里的实际问题是OpenMP标准没有定义默认调度。这是实现定义的...对于默认调度为dynamic
的(很多)实现,代码段中不能有任何竞争条件。但是,如果默认调度为HTTP Error 404. The requested resource is not found.
,则您会注意到,会发生竞争情况,并且结果不确定。