在x86中暂停指令

我正在尝试创build自旋锁的哑版。 浏览网页时,我遇到了x86中的汇编指令,这个指令用于向处理器提示当前在该CPU上正在运行旋转locking。 英特尔手册和其他可用信息状态

The processor uses this hint to avoid the memory order violation in most situations, which greatly improves processor performance. For this reason, it is recommended that a PAUSE instruction be placed in all spin-wait loops. The documentation also mentions that "wait(some delay)" is the pseudo implementation of the instruction. 

上段的最后一行是直观的。 如果我没有成功抓住锁,我必须等待一段时间,然后再次抓住锁。

但是,在自旋锁的情况下,由于内存顺序违反,我们是什么意思? “内存顺序违规”是指旋转锁后指令的不正确的推测加载/存储?

仅供参考,自旋locking问题已被问到堆栈溢出之前,但内存秩序违反问题仍然没有得到答复…至less为我的理解

试想一下,处理器如何执行一个典型的自旋等待循环:

 1 Spin_Lock: 2 CMP lockvar, 0 ; Check if lock is free 3 JE Get_Lock 4 JMP Spin_Lock 5 Get_Lock: 

经过几次迭代后,分支预测器将预测条件分支(3)将永远不会被采用,并且stream水线将填充CMP指令(2)。 这一直持续到最后另一个处理器写一个零来lockingvar。 在这一点上,我们有充满推测(即未提交)的CMP指令的stream水线,其中一些已经读取lockvar并向以下条件分支(3)(也是推测性的)报告了(不正确的)非零结果。 这是内存顺序违规发生的时候。 每当处理器“看到”一个外部写入(来自另一个处理器的写入)时,它在其stream水线中search推测性地访问相同存储器位置并且还没有提交的指令。 如果发现任何这样的指令,那么处理器的推测状态是无效的,并且在stream水线刷新的情况下被擦除。

不幸的是,这种情况很可能会在处理器每次等待自旋锁时重复进行,并且使得这些锁的速度比他们本应该慢的多。

inputPAUSE指令:

 1 Spin_Lock: 2 CMP lockvar, 0 ; Check if lock is free 3 JE Get_Lock 4 PAUSE ; Wait for memory pipeline to become empty 5 JMP Spin_Lock 6 Get_Lock: 

PAUSE指令将“去stream水线化”存储器读取,使得stream水线没有像第一个例子那样用推测CMP(2)指令填充。 (即它可以阻塞stream水线,直到所有较旧的存储器指令被提交为止)。因为CMP指令(2)顺序执行,所以在CMP指令(2)读之后发生外部写入的可能性(即时间窗口短得多) lockvar,但在CMP之前。

当然“去stream水线”也会浪费更less的能量在旋转locking和超线程的情况下,不会浪费资源,其他线程可以使用得更好。 另一方面,在每个循环退出之前还有一个分支预测错误。 英特尔的文档不build议暂停消除pipe道冲洗,但谁知道…

Interesting Posts