与`std :: mutex`同步慢于`std :: atomic(memory_order_seq_cst)`?

时间:2013-04-30 20:20:50

标签: c++ c++11 concurrency memory-model compare-and-swap

在互斥量上使用原子的主要原因是互斥量很昂贵,但atomics的默认内存模型是memory_order_seq_cst,这不是很贵吗?

问题:使用锁的程序可以和并发无锁程序一样快吗?

如果是这样,除非我想将memory_order_acq_rel用于原子,否则可能不值得。


编辑: 我可能会遗漏一些东西,但基于锁定的速度比无锁更快,因为每个锁也必须是一个完整的内存屏障。但是,通过无锁,可以使用比内存障碍更少限制的技术。

回到我的问题,除了基于新的C ++ 11标准的默认memory_model的锁定之外,锁定是否更快?

“无锁定> =基于锁定时的性能测量”是真的吗?我们假设有2个硬件线程。


编辑2: 我的问题不是关于进度保证,也许我正在使用“无锁”脱离上下文。

基本上当你有2个带有共享内存的线程时,你需要的唯一保证就是如果一个线程在写,那么另一个线程无法读或写,我的假设是一个简单的原子compare_and_swap操作比锁定互斥锁要快得多。

因为如果一个线程甚至没有触及共享内存,你将无缘无故地反复锁定和解锁,但是使用原子操作,每次只使用1个CPU周期。

关于注释,当争用很少时,自旋锁与互斥锁是非常不同的。

3 个答案:

答案 0 :(得分:53)

Lockfree编程是关于进度保证:从最强到最弱,那些无等待无锁阻塞-free 阻止

保证价格昂贵且价格合理。您想要的保证越多,您支付的费用就越多。通常,阻塞算法或数据结构(例如,使用互斥体)具有最大的自由度,因此可能是最快的。另一个极端的无等待算法必须在每一步使用原子操作,这可能要慢得多。

获得锁定实际上相当便宜,所以如果不深入了解主题,就不应该担心。此外,使用互斥锁的阻塞算法很多更容易阅读,编写和推理。相比之下,即使是最简单的无锁数据结构也是长期专注研究的结果,每个研究都值得一个或多个博士。

简而言之,锁定或无等待算法会导致平均延迟和吞吐量的最差延迟。一切都比较慢,但没有什么东西非常慢。这是一个非常特殊的特性,仅在非常特殊的情况下(如实时系统)才有用。

答案 1 :(得分:2)

锁定往往比简单的原子操作需要更多的操作。在最简单的情况下,memory_order_seq_cst的速度大约是锁定的两倍,因为锁定往往需要,在其实现中至少需要两个原子操作(一个锁定,一个解锁)。在许多情况下,它甚至需要更多。但是,一旦开始利用内存订单,它就会快得多,因为您愿意接受较少的同步。

此外,您经常会看到“锁定算法始终与无锁算法一样快”。这有点真实。基本的想法是,如果最快的算法恰好是无锁,那么没有无锁保证的最快算法也是同样的算法!但是,如果最快的algortihm需要锁定,那么那些要求无锁保证的人必须找到一个更慢的算法。

通常,您将在一些低级算法中看到无锁算法,其中利用专用操作码的性能有所帮助。在几乎所有其他代码中,锁定不仅仅是令人满意的性能,而且更容易阅读。

答案 2 :(得分:0)

  

问题:使用锁并发程序是否可以和锁一样快   并发无锁程序?

它可能会更快:无锁算法必须始终使全局状态保持一致状态,并且在执行计算时不知道它们是否会有效,因为在完成计算时状态可能已经改变,从而使其变得无关紧要,丢失了CPU周期。

无锁策略使序列化过程在计算完成时在过程结束时发生。在病理情况下,许多线程可以做一个工作,只有一个工作有成果,而其他工作会重试。

无锁可能导致某些线程处于饥饿状态,无论它们的优先级是多少,都无法避免。 (尽管除非出现疯狂的争用,否则线程不太可能饿死重试很长时间。)

另一方面,“基于序列化计算和一系列基于副作用的(又名基于锁定)算法” 在他们知道其他参与者不会阻止他们对该特定锁定资源进行操作之前不会启动 strong>(通过使用互斥量提供保证)。请注意,如果使用了多个锁,则可能由于需要访问另一个资源而无法完成它们,如果在设计不良的程序中需要多个锁,则会导致死锁。

请注意,此死锁问题不在无锁代码范围之内,后者甚至无法作用于多个实体:它通常无法基于两个不相关的对象进行原子提交(1)。

因此无锁代码缺少死锁的机会是无锁代码弱点的标志:无法死锁是您工具的局限。一次只能拥有锁的系统也将无法死锁。

与基于锁的算法相比,无锁算法的范围很小。对于很多问题,无锁甚至毫无意义。

基于锁的算法是有礼貌的,线程在执行所需操作之前必须排队等待:这在每个线程的计算步骤方面效率最高。强>。但是必须在等待列表中排队线程效率低下:他们通常无法使用时间片的结尾,因此效率非常低下,因为有人试图做严肃的工作,而总是被电话打扰:他的注意力消失了,他永远无法达到最高效率,因为他的工作时间被切成小块。

(1)您至少需要 能够执行双重CAS,即对两个任意地址执行原子操作(而不是双重字CAS,这只是一个在更多位上执行CAS,可以轻松实现到缓存行的自然CPU内存访问仲裁单元。