C ++
我正在用c ++编写一个多线程应用程序,其中性能至关重要。 我需要在线程之间复制小结构时使用大量锁定,因为我选择使用自旋锁。
我已经做了一些研究和速度测试,我发现大多数实现大致同样快速:
__asm {}
来使用一些内联汇编,它的分数大约是70个时间单位, 但我不确定是否已经创建了适当的内存屏障。 编辑:这里给出的时间是两个线程锁定和解锁百万次螺旋锁所花费的时间。
我知道这并没有太大的区别,但由于自旋锁是一个被广泛使用的对象,人们会认为程序员会以最快的方式达成自旋锁定。 谷歌搜索导致许多不同的方法,但是。 如果使用内联汇编并使用指令CMPXCHG8B
而不是比较32位寄存器来实现,我会认为这种上述方法是最快的。 此外,必须考虑内存屏障,这可以通过LOCK CMPXHG8B(我认为?)来完成 ,它保证了内核之间共享内存的“独占权”。 最后(有人建议)对于繁忙的等待应该伴随着NOP:REP ,这将使超线程处理器切换到另一个线程,但我不确定这是否是真的?
从我对不同自旋锁的性能测试中可以看出,没有太大的差别,但为了纯学术目的,我想知道哪一个最快。 然而,由于我在汇编语言和内存障碍方面的经验非常有限,如果有人能够为我在LOCK CMPXCHG8B中提供的最后一个示例编写汇编代码并在以下模板中使用适当的内存屏障 ,我会很高兴:
__asm
{
spin_lock:
;locking code.
spin_unlock:
;unlocking code.
}
看看这里:使用cmpxchg的x86 spinlock
感谢Cory Nelson
__asm{
spin_lock:
xorl %ecx, %ecx
incl %ecx
spin_lock_retry:
xorl %eax, %eax
lock; cmpxchgl %ecx, (lock_addr)
jnz spin_lock_retry
ret
spin_unlock:
movl $0 (lock_addr)
ret
}
另有消息称:http://www.geoffchappell.com/studies/windows/km/cpu/cx8.htm
lock cmpxchg8b qword ptr [esi]
is replaceable with the following sequence
try:
lock bts dword ptr [edi],0
jnb acquired
wait:
test dword ptr [edi],1
je try
pause ; if available
jmp wait
acquired:
cmp eax,[esi]
jne fail
cmp edx,[esi+4]
je exchange
fail:
mov eax,[esi]
mov edx,[esi+4]
jmp done
exchange:
mov [esi],ebx
mov [esi+4],ecx
done:
mov byte ptr [edi],0
这里是关于无锁vs锁实现的讨论:http://newsgroups.derkeiler.com/Archive/Comp/comp.compogramming.threads/2011-10/msg00009.html
虽然已经有了一个可以接受的答案,但有些东西可能会被用来改善所有答案,从以下英特尔文章中可以看出,以上都是快速锁定实现:
维基百科在spinlocks上有一篇很好的文章,这里是x86的实现
http://en.wikipedia.org/wiki/Spinlock#Example_implementation
注意它们的实现不使用“lock”前缀,因为它在xchg指令的x86上是冗余的 - 它隐含地具有锁定语义,正如此Stackoverflow讨论中所讨论的:
在多核x86上,是否需要LOCK作为XCHG的前缀?
REP:NOP是PAUSE指令的别名,您可以在这里了解更多信息
x86如何暂停spinlock中的指令工作*和*是否可以在其他场景中使用?
关于记忆障碍的问题,这里是你可能想知道的一切
内存障碍:Paul E. McKenney的软件黑客硬件视图
http://irl.cs.ucla.edu/~yingdi/paperreading/whymb.2010.06.07c.pdf
链接地址: http://www.djcxy.com/p/64597.html上一篇: c++