OpenMP 中的同步
Posted
技术标签:
【中文标题】OpenMP 中的同步【英文标题】:Synchronization in OpenMP 【发布时间】:2015-10-14 05:07:49 【问题描述】:我正在尝试使用 OpenMP 实现并行算法。 原则上,我应该有许多线程以异步方式写入和读取共享向量的不同组件。 有一个 FOR 循环,其中线程循环,当线程在循环的行 A 中时,它写入共享向量的随机分量,而当它在行 B 中时,它读取循环的随机分量相同的共享向量。 一个线程可能会尝试读取共享向量的一个组件,而该组件是由另一个线程编写的。 如何避免不一致?
我阅读了有关锁和临界区的信息,但我认为这不是解决方案。例如,我可以围绕线程在共享向量中写入的 A 行设置锁定,但是如果 B 行中的线程同时尝试读取该组件,这是否可以防止不一致?
【问题讨论】:
向量不是线程安全的,因此您的数据竞争情况可能会发生。我认为最好的解决方案(如果可能的话)是将向量简单地分成多个部分并将这些部分分配给不同的线程。这样,您就不需要任何锁或原子,因为每个线程都有自己的个人向量子部分。 “假设循环的 A 行它写在共享向量的随机分量上,而当它在 B 行时,它读取同一共享向量的随机分量”:与可能的不一致,您的算法对此有弹性吗?我的意思是,对“共享向量的随机分量”进行读写操作的顺序是否会对最终结果产生严重影响?如果是的话,也许你的算法毕竟不是可并行的(这种方式)。如果没有,可能有一个解决方案。只需发布一个有效的顺序版本,我们就会看到。 请显示minimal but working example of what you want to do。至少显示标量代码。 【参考方案1】:如果向量修改是非常简单的单值赋值操作并且实际上不是函数调用,那么您需要的可能是原子读取和写入。使用原子操作,从同时写入的数组元素中读取将返回新值或先前值;它永远不会返回某种旧值和新值的混合。 OpenMP 为此提供了atomic
构造。在某些架构(包括 x86)上,原子比临界区轻得多。
对于更复杂的修改,您必须使用关键部分。这些可以是命名的或匿名的。后者是使用
创建的#pragma omp critical
code block
匿名临界区都映射到同一个同步对象,无论结构在源代码中的位置如何,因此不相关的代码部分可能会与所有可能的不良影响同步,例如性能下降甚至意外僵局。这就是为什么建议总是使用命名的关键部分。例如,以下两个代码段将不同步:
// -- thread i -- // -- thread j --
... ...
#pragma omp critical(foo) < #pragma omp critical(foo)
do_something(); < do_something;
... ...
#pragma omp critical(bar) #pragma omp critical(bar) <
do_something_else(); do_something_else(); <
... ...
(每个线程当前正在执行的代码标有<
)
请注意,临界区绑定到程序的所有线程,而不考虑线程所属的团队。这意味着即使是在不同并行区域中执行的代码(这种情况主要在使用嵌套并行时出现)也会被同步。
【讨论】:
以上是关于OpenMP 中的同步的主要内容,如果未能解决你的问题,请参考以下文章