The PAUSE
指令是 x86 特定的。它是sole use处于自旋锁等待循环中,其中:
提高了自旋等待循环的性能。当执行“自旋等待循环”时,处理器在退出循环时将遭受严重的性能损失,因为它检测到可能的内存顺序违规。 PAUSE 指令向处理器提示代码序列是一个自旋等待循环。
Also:
在 spinwait 循环中插入暂停指令可以大大降低处理器的功耗。
将此指令放入自旋锁循环中的位置也是特定于 x86_64 的。我不能代表 C++11 标准人员发言,但我认为他们得出这样的结论是合理的:这个魔法的正确位置是在相关库中......以及实现原子、互斥等所需的所有其他魔法。
NB: the PAUSE
does not释放处理器以允许另一个线程运行。这是not一个“低级”pthread_yield()
。 (尽管在 Intel 超线程核心上,它确实可以防止自旋锁线程占用核心。)PAUSE
似乎是关闭通常的指令执行优化和流水线,这会减慢线程速度(有点),但是发现锁正忙,这会降低接触锁变量的速率,从而使缓存系统当锁的当前所有者正在尝试继续实际工作时,不会被服务员敲打。
请注意,用于“手动滚动”自旋锁、互斥体等的原语不是特定于操作系统的,而是特定于处理器的。
我不确定我是否会将“手卷”自旋锁描述为“无锁”!
FWIW,英特尔对自旋锁的建议(“英特尔® 64 和 IA-32 架构优化参考手册") is:
Spin_Lock:
CMP lockvar, 0 // Check if lock is free.
JE Get_lock
PAUSE // Short delay.
JMP Spin_Lock
Get_Lock:
MOV EAX, 1
XCHG EAX, lockvar // Try to get lock.
CMP EAX, 0 // Test if successful.
JNE Spin_Lock
显然,人们可以使用 a 来编写一些可以编译成这样的东西std::atomic_flag
...或使用pthread_spin_lock()
,在我的机器上是:
pthread_spin_lock:
lock decl (%rdi)
jne wait
xor %eax, %eax
ret
wait:
pause
cmpl $0, (%rdi)
jg pthread_spin_lock
jmp wait
这真的很难挑剔。