OpenMP中的原子和关键有什么区别?

cod*_*ons 103 atomic openmp critical-section

OpenMP中的原子和关键有什么区别?

我可以做这个

#pragma omp atomic
g_qCount++;
Run Code Online (Sandbox Code Playgroud)

但是不一样

#pragma omp critical
g_qCount++;
Run Code Online (Sandbox Code Playgroud)

Jon*_*rsi 164

对g_qCount的影响是相同的,但所做的是不同的.

OpenMP临界区是完全通用的 - 它可以包围任意代码块.但是,每次线程进入和退出临界区时(除了序列化的固有成本之外),都会因此产生大量开销.

(此外,在OpenMP中,所有未命名的关键部分都被认为是相同的(如果您愿意,所有未命名的关键部分只有一个锁),因此,如果一个线程位于上面的一个[未命名]临界区中,则没有任何线程可以进入任何[未命名]关键部分.正如您可能猜到的那样,您可以通过使用命名的关键部分来解决这个问题.

原子操作的开销要低得多.在可用的情况下,它利用提供(比如说)原子增量操作的硬件; 在这种情况下,进入/退出代码行时不需要锁定/解锁,它只是硬件告诉你的原子增量不会受到干扰.

好处是开销要低得多,并且原子操作中的一个线程不会阻止任何(不同的)原子操作即将发生.缺点是原子支持的有限操作集.

当然,在任何一种情况下,都会产生序列化的成本.

  • "你可以放松便携性" - 我不确定这是真的.[标准(版本2.0)](http://www.openmp.org/mp-documents/cspec20.pdf)指定允许哪些原子操作(基本上类似于`++`和`*=`),如果它们在硬件中不受支持,它们可能被"关键"部分取代. (5认同)

Mic*_*ael 27

在OpenMP中,所有未命名的关键部分都是互斥的.

关键和原子之间最重要的区别是原子只能保护单个赋值,您可以将它与特定运算符一起使用.

  • 这最好是对前一个答案的评论(或编辑). (13认同)

小智 16

关键部分:

  • 确保代码块的序列化.
  • 可以通过正确使用"name"标记扩展到序列化块组.

  • 慢点!

原子操作:

  • 快得多!

  • 仅确保特定操作的序列化.

  • 这个答案没有添加任何新信息. (11认同)
  • 但这个答案是非常易读的,将是第一个答案的一个很好的总结 (9认同)

小智 7

最快的方法既不重要也不原子.大约,添加临界部分比简单添加贵200倍,原子添加比简单添加贵25倍.

最快的选择(并不总是适用)是为每个线程提供自己的计数器,并在需要总和时进行减少操作.

  • 我不同意你在解释中提到的所有数字.假设x86_64,原子操作将有一些周期开销(同步缓存线)大约一个周期的成本.如果你本来会有"真正的共享"成本,那么开销就是虚无... 关键部分会产生锁定成本.根据是否已经采取锁定,开销大约是2个原子指令或调度程序的两次运行和休眠时间 - 通常会大大超过200x. (2认同)

dar*_*rda 5

限制atomic很重要.它们应该在OpenMP规范中详细说明.MSDN提供快速备忘单,因为如果不改变我也不会感到惊讶.(Visual Studio 2012自2002年3月开始实施OpenMP.)引用MSDN:

表达式语句必须具有以下形式之一:

xbinop =expr

x++

++x

x--

--x

在前面的表达式中:x是一个lvalue标量类型的表达式.expr是一个标量类型的表达式,它不引用指定的对象x.binop不是一个重载操作,是中的一个+,*,-,/,&,^,|,<<,或>>.

我建议您尽可能使用atomic,否则命名为关键部分.命名它们很重要; 你会避免以这种方式调试头痛.