各种无锁算法在快速路径中没有加载或存储排序要求。例如,在这个工作窃取http://www.cs.rice.edu/~vs3/PDF/ppopp.09/p45-michael.pdf中,窃取操作需要原子比较和交换,但频繁的操作(put and take) 专门设计为不需要任何排序约束。在许多其他情况下,我遇到过这种模式。
那么为什么在不强制内存限制的情况下就无法访问 std 原子变量呢?虽然在 x-86(-64) 上 memory_order_relaxed 不会插入任何 CPU 屏障指令,但它会阻止编译器重新排序(至少从我在 Visual C++ 2012 实现中看到的内容来看),这仍然肯定会产生负面性能。事实上,由于内存顺序是一个运行时参数,因此也会产生分支的惩罚。结合起来,这使事情变得更糟。下面是 Visual C++ 2012 实现中的代码,它在 switch 语句确定它是 memory_order_relaxed 之后将 uint32_t 值存储到 atomic_uint32_t 中(参见 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 进行一些编译时检查?
(请注意,我不是在谈论混合原子访问和非原子访问,因为我关心的是整数类型,其正常加载和存储在我的目标架构上已经是原子的。)