在某些方面,这似乎是一个家庭作业问题,我讨厌为人们做。另一方面,上面的答案并不完全准确,我觉得应该纠正。
首先,虽然在这个例子中共享和私人条款都不需要,我不同意康拉德他们不应该使用。人们并行化代码最常见的问题之一是,他们没有花时间来理解变量是如何被使用的。不是私有化和/或保护应该是的共享变量,这是我看到的最多问题。仔细研究如何使用变量并将它们放入合适的共享,私有等子句中,将大大减少您遇到的问题的数量。
至于有关障碍的问题,第一个循环可以有一个nowait子句,因为在第二个循环中没有使用计算的值(a)。只有在计算值(即,不存在依赖关系)之前计算出的值(c)未被使用时,第二循环才可以具有nowait子句。在原始示例代码中,第二个循环中有一个nowait,但是在第三个循环之前有一个显式屏障。这很好,因为你的教授试图表明使用明确的屏障 - 尽管在第二个循环中离开了nowait会使得明确的屏障是多余的(因为在循环结尾有一个隐含的屏障)。
另一方面,根本不需要第二回路和显式屏障可能根本不需要。在OpenMP V3.0规范之前,许多人认为规范中没有阐明某些事情是真实的。随着OpenMP的V3.0规格如下加入部分2.5.1循环结构,表2-1进度条样值,静态(时间表):
一个兼容的实现静态调度必须保证如果满足以下条件,将在两个循环 区域中使用相同的 将逻辑迭代号分配给线程:1)两个循环区域都具有相同数量的循环迭代,2)两个循环区域具有相同的值 指定了chunk_size,或者两个循环区域没有指定chunk_size,并且3)两个循环区域都绑定到相同的并行区域。 之间的数据依赖性在两个这样的循环中的相同的逻辑迭代被保证满足 允许安全地使用nowait子句(参见关于 示例的第170页的A.9节)。
现在在你的例子中,任何循环都没有显示任何时间表,所以这可能会也可能不会成立。原因是,默认时间表是实现定义的,而大多数实现当前将默认时间表定义为静态,但不能保证这一点。如果你的教授在所有三个循环中都有一个没有chunk-size的静态调度类型,那么nowait可以用在第一个和第二个循环上,而第二个和第二个循环之间不需要任何屏障(隐式或显式)第三个循环。
现在我们来到第三个循环以及关于nowait和reduce的问题。正如Michy指出的那样,OpenMP规范允许指定(还原和nowait)。但是,减少完成并不需要同步。在示例中,可以使用nowait删除隐式屏障(在第三个循环结束时)。这是因为在并行区域的隐式屏障遇到之前,还原(和)未被使用。
如果你看的OpenMP V3.0规范,第2.9.3.6条款减少,你会发现以下内容:
如果不使用NOWAIT,减少计算将在年底前完成 构造;然而,如果在还应用了nowait的构造上使用了reduction clause,那么对原始列表项的访问将创建一个竞赛,并因此具有 未指定的效果,除非同步确保在所有线程都执行完所有线程后执行 他们的迭代或部分结构,并且减少计算 已经完成并存储了该列表项目的计算值。这可以通过障碍同步确保最简单的 。
这意味着如果您想在第三次循环之后在并行区域中使用sum变量,那么您在使用它之前需要一个屏障(隐式或显式)。如现在的例子,这是正确的。
来源
2011-06-12 18:45:23
ejd
我很好奇,你在哪里找到这个例子? – 2011-06-11 12:31:30
这个例子是我的教授给出的。这是为了解释明确的障碍的使用,但我不确定最终的回路是否正确。 – aperez 2011-06-11 12:35:33