各种无锁算法在快速路径中没有加载或存储排序要求。例如,在这个窃取工作http://www.cs.rice.edu/~vs3/PDF/ppopp.09/p45-michael.pdf中,窃取操作需要原子比较和交换,但是频繁的操作(put和take)专门设计为不需要任何排序约束。在许多其他情况下,我遇到过这种模式。
那么为什么没有强制执行内存约束就无法访问std原子变量?虽然在x-86(-64)上memory_order_relaxed没有插入任何CPU屏障指令,但它会阻止编译器重新排序(至少从我在Visual C ++ 2012实现中看到的内容),这仍然肯定会有负面的性能。实际上,由于存储器顺序是运行时参数,因此还存在分支的罚分。结合起来,这会让事情变得更糟。这是在Visual C ++ 2012实现中将一个uint32_t值存储到atomic_uint32_t中的代码,在switch语句确定它的memory_order_relaxed之后(参见xatomic.h):
_Compiler_barrier();
__asm
{
mov eax, _Value;
mov edx, _Tgt;
mov [edx], eax;
}
_Compiler_barrier();
带有memory_order_relaxed的加载然后结束执行
_Value = _InterlockedOr((volatile long *)_Tgt, 0);
这更糟糕,因为_InterlockedOr内在是一个完整的CPU障碍(xatomic.h)。
所以,1)为什么非内存有序访问不是std API的一部分,2)除了滚动自己的原子API之外还有什么解决办法,除了丑陋的reinterpret_cast之外原子类为非原子类型,并对sizeof和offsetof进行一些编译时检查?
(请注意,我并不是在谈论混合原子访问和非原子访问,因为我关注的是整数类型,其正常的加载和存储在我所针对的体系结构上已经是原子的。)