旋锁,它们有用吗?

33 c# c++ multithreading locking spinlock

您经常在代码中发现自己使用自旋锁的频率是多少?遇到使用繁忙循环实际上优于锁的使用情况的情况有多常见?
就个人而言,当我编写某种需要线程安全的代码时,我倾向于使用不同的同步原语对其进行基准测试,并且就其而言,使用锁似乎比使用自旋锁具有更好的性能.无论我实际持有锁的时间有多少,使用自旋锁时我收到的争用量远大于使用锁时获得的数量(当然,我在多处理器机器上运行我的测试).

我意识到它更有可能在"低级"代码中遇到一个螺旋锁,但我很想知道你是否发现它甚至可以用于更高级的编程?

jal*_*alf 35

这取决于你在做什么.在一般的应用程序代码中,您需要避免螺旋锁.

在低级别的东西中,你只需要锁定几条指令,并且延迟很重要,螺旋锁是一种比锁更好的解决方案.但这些情况很少见,尤其是在通常使用C#的应用程序中.

  • 特别是,如果你有多个核心,那么旋转一个核心等待另一个核心可能会比激发重新安排更快,更快.如果您有很多争用,上下文切换可以加起来.单核,自旋锁不太引人注目,因为它等于放弃剩余的时间片,而不会让下一个线程进入直到它到期,所以它相当于一个非常缓慢的产量... (27认同)

Ree*_*sey 20

在C#中,根据我的经验,"自旋锁"几乎总是比锁定更糟糕 - 这种情况很少发生,其中自旋锁的性能优于锁.

然而,情况并非总是如此..NET 4正在添加System.Threading.SpinLock结构.这在锁定被保持很短时间并被反复抓取的情况下提供了益处.从用于并行编程的数据结构的MSDN文档:

在预计等待锁定较短的情况下,SpinLock提供比其他形式的锁定更好的性能.

在您执行诸如锁定树之类的操作的情况下,旋转锁可以胜过其他锁定机制 - 如果您在非常短的时间内仅在每个节点上锁定,则它们可以执行传统锁定.我在一个带有多线程场景更新的渲染引擎中遇到了这个问题 - 在某一点上 - 旋转锁被分析出来以超越与Monitor.Enter的锁定.


T.E*_*.D. 11

对于我的实时工作,尤其是设备驱动程序,我已经使用了它们.事实证明(当我最后一次计时)等待与硬件中断相关的信号量这样的同步对象至少咀嚼20微秒,无论中断实际发生多长时间.对存储器映射的硬件寄存器进行单次检查,然后检查RDTSC(允许超时以便不锁定机器)处于高纳秒范围内(基本上在噪声中).对于不应该花费太多时间的硬件级握手,要击败自旋锁是非常困难的.


Rem*_*anu 9

我的2c:如果你的更新满足一些访问标准,那么它们是好的螺旋锁候选者:

  • ,即你将有时间获得自旋锁,执行更新并在单个线程量子中释放自旋锁,这样你就不会在握住自旋锁时被抢占
  • 本地化您更新的所有数据最好都是一个已加载的单页,您不希望在持有自旋锁的情况下TLB未命中,并且您定义不希望页面错误交换读取!
  • 原子你不需要任何其他锁来执行操作,即.永远不要等待自旋锁下的锁.

对于任何有可能产生的东西,您应该使用通知的锁结构(事件,互斥,信号量等).


dsi*_*cha 7

旋转锁的一个用例是,如果你期望非常低的争用,但会有很多.如果您不需要支持递归锁定,则可以在单个字节中实现自旋锁,如果争用非常低,则CPU周期浪费可以忽略不计.

对于实际用例,我经常有数千个元素的数组,其中对数组的不同元素的更新可以安全地并行发生.两个线程试图同时更新同一个元素的几率非常小(低争用)但我需要为每个元素锁定一个(我将会有很多).在这些情况下,我通常会分配一个与我正在并行更新的数组大小相同的ubytes数组,并实现内联的自旋锁(在D编程语言中):

while(!atomicCasUbyte(spinLocks[i], 0, 1)) {}
    myArray[i] = newVal;
atomicSetUbyte(spinLocks[i], 0);
Run Code Online (Sandbox Code Playgroud)

另一方面,如果我必须使用常规锁,我将不得不分配一个指向Object的指针数组,然后为该数组的每个元素分配一个Mutex对象.在如上所述的场景中,这只是浪费.


Ben*_*Ben 5

请注意以下几点:

  1. 大多数互斥体的实现会在线程实际未调度之前旋转一段时间。因此,很难将这些互斥锁与纯自旋锁进行比较。

  2. 在同一个自旋锁上“尽可能快地”旋转的多个线程将占用所有带宽并大大降低您的程序效率。您需要通过在旋转循环中添加 noop 来增加微小的“睡眠”时间。


Jor*_*ren 5

如果你有性能关键代码并且你已经确定它需要比现在更快并且你已经确定关键因素是锁定速度,那么尝试自旋锁是个好主意.在其他情况下,为什么要这么麻烦?正常锁更容易正确使用.