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();       <
...                                ...

(每个线程当前正在执行的代码标有&lt;

请注意,临界区绑定到程序的所有线程,而不考虑线程所属的团队。这意味着即使是在不同并行区域中执行的代码(这种情况主要在使用嵌套并行时出现)也会被同步。

【讨论】:

以上是关于OpenMP 中的同步的主要内容,如果未能解决你的问题,请参考以下文章

使用编译器内在函数实现自旋锁以同步 OpenMP 线程

在 openMP 中,如何确保线程在继续之前同步?

OpenMP C++ 中的线程

OpenMP 中的“静态”和“动态”调度有啥区别?

C++:OpenMP 中的私有静态变量

OpenMP 中的分析/调试 - Linux 和免费?