jal*_*alf 35
这取决于你在做什么.在一般的应用程序代码中,您需要避免螺旋锁.
在低级别的东西中,你只需要锁定几条指令,并且延迟很重要,螺旋锁是一种比锁更好的解决方案.但这些情况很少见,尤其是在通常使用C#的应用程序中.
Ree*_*sey 20
在C#中,根据我的经验,"自旋锁"几乎总是比锁定更糟糕 - 这种情况很少发生,其中自旋锁的性能优于锁.
然而,情况并非总是如此..NET 4正在添加System.Threading.SpinLock结构.这在锁定被保持很短时间并被反复抓取的情况下提供了益处.从用于并行编程的数据结构的MSDN文档:
在预计等待锁定较短的情况下,SpinLock提供比其他形式的锁定更好的性能.
在您执行诸如锁定树之类的操作的情况下,旋转锁可以胜过其他锁定机制 - 如果您在非常短的时间内仅在每个节点上锁定,则它们可以执行传统锁定.我在一个带有多线程场景更新的渲染引擎中遇到了这个问题 - 在某一点上 - 旋转锁被分析出来以超越与Monitor.Enter的锁定.
T.E*_*.D. 11
对于我的实时工作,尤其是设备驱动程序,我已经使用了它们.事实证明(当我最后一次计时)等待与硬件中断相关的信号量这样的同步对象至少咀嚼20微秒,无论中断实际发生多长时间.对存储器映射的硬件寄存器进行单次检查,然后检查RDTSC(允许超时以便不锁定机器)处于高纳秒范围内(基本上在噪声中).对于不应该花费太多时间的硬件级握手,要击败自旋锁是非常困难的.
我的2c:如果你的更新满足一些访问标准,那么它们是好的螺旋锁候选者:
对于任何有可能产生的东西,您应该使用通知的锁结构(事件,互斥,信号量等).
旋转锁的一个用例是,如果你期望非常低的争用,但会有很多.如果您不需要支持递归锁定,则可以在单个字节中实现自旋锁,如果争用非常低,则CPU周期浪费可以忽略不计.
对于实际用例,我经常有数千个元素的数组,其中对数组的不同元素的更新可以安全地并行发生.两个线程试图同时更新同一个元素的几率非常小(低争用)但我需要为每个元素锁定一个(我将会有很多).在这些情况下,我通常会分配一个与我正在并行更新的数组大小相同的ubytes数组,并实现内联的自旋锁(在D编程语言中):
while(!atomicCasUbyte(spinLocks[i], 0, 1)) {}
myArray[i] = newVal;
atomicSetUbyte(spinLocks[i], 0);
Run Code Online (Sandbox Code Playgroud)
另一方面,如果我必须使用常规锁,我将不得不分配一个指向Object的指针数组,然后为该数组的每个元素分配一个Mutex对象.在如上所述的场景中,这只是浪费.
请注意以下几点:
大多数互斥体的实现会在线程实际未调度之前旋转一段时间。因此,很难将这些互斥锁与纯自旋锁进行比较。
在同一个自旋锁上“尽可能快地”旋转的多个线程将占用所有带宽并大大降低您的程序效率。您需要通过在旋转循环中添加 noop 来增加微小的“睡眠”时间。