请提出一个后续问题 为什么这个 "std::atomic_thread_fence "能用?
作为一个假人联锁操作比 _mm_mfence
,而且有不少实现方式,应该使用哪种联锁操作,在什么数据上使用?
假设使用一个内联汇编,它不知道周围的上下文,但可以告诉编译器它clobbers了哪些寄存器。
暂时简答,不说太详细的原因。 具体请看 论语 在那个链接的问题上。
lock orb $0, -1(%rsp)
可能是一个不错的选择,以避免延长被spilledreloaded的本地变量的依赖链。参见 https:/shipilev.netblog2014on-the-fence-with-dependencies(依赖性) 为基准。 在Windows x64上(无红区),除了未来的呼叫或推送指令外,该空间应未被使用。
存储转发 到 负载方 lock
ed操作可能是一件事(如果那个空间最近被使用了),所以保持锁定操作的狭窄是好的。 但是作为一个完整的屏障,我不期望可以有任何存储转发从它的输出到其他任何东西,所以与正常的不同,一个狭窄的(1字节)的 lock orb
并没有这个缺点。
mfence
是很垃圾的,即使在Haswell上也是堆栈空间的热线,在Skylake上可能更糟糕,它甚至阻挡了OOO exec.(在AMD上也很糟糕,相比于 lock add
).
在走假人位置联锁操作的路线时,需要考虑的问题不多。
如果没有上下文,任何事情都只能是猜测,所以我们的目标是做一个最好的猜测。
靠近栈顶的地方是1和2的好猜测。
刻意分配的堆栈变量很可能解决3,由于没有其他存储在飞行中,4不是问题。最好的操作是这样的 lock not
.
不分配堆栈变量要求操作实际上是no-op,所以 lock or [mem], 0
是一个不错的选择。操作数应该是字节,以避免4的问题,对于3,总是猜测。(虽然可以使用返回地址,但没有上下文的汇编不知道。但是MSVC _AddressOfReturnAddress
可能是个好主意)
我读过关于红区的文章。在Windows上没有红区可以进行额外的优化。
lock not byte ptr [esp-1]
没有额外的变量在Windows上是很好的,因为数据被认为是不稳定的,不应该被使用。没有溢出的寄存器,所以没有错误的数据依赖。
有128字节红区的ABI排除了使用 "红区 "的可能性。lock not byte ptr [esp-1]
. 超出栈的128个字节很可能不是L1d。不过,由于红色区域不太可能被用作通常的堆栈,@Peter Cordes给出的答案看起来不错。
TSX主要是由于它的缺失(在给定的CPU上不支持,或者由于勘误修正或安全缓解而被禁用)而受到质疑。在可预见的未来,只有RTM会存在(硬件锁Elision是否因Spectre Mitigation而永远消失了?). 根据 RTM概述,一个空的RTM事务仍然是一个栅栏,所以它可以被使用。
一个成功提交的RTM区域由一个XBEGIN和一个XEND组成,即使RTM区域内没有任何内存操作,其排序语义也与LOCK前缀指令相同。
小心失败的事务或不支持的RTM。伪代码似乎如下。
if (rtm_supported && _xbegin() == 0xFFFFFFFF)
_xend();
else
dummy_interlocked_op();