众所周知,在x86架构上,对于操作load()和store(),内存屏障memory_order_consume、memory_order_acquire、memory_order_release和memory_order_acq_rel不需要处理器缓存和流水线的指令,汇编代码总是对应于std::memory_order_relaxed。这些限制只是为了编译器的优化而必要:http://www.stdthread.co.uk/forum/index.php?topic=72.0
而这段反汇编代码证实了对于store() (MSVS2012 x86_64),上述观点的正确性:
std::atomic<int> a;
a.store(0, std::memory_order_relaxed);
000000013F931A0D mov dword ptr [a],0
a.store(1, std::memory_order_release);
000000013F931A15 mov dword ptr [a],1
但是这段代码没有为 load()
(MSVS2012 x86_64)进行确认,而是使用了 lock cmpxchg
:
int val = a.load(std::memory_order_acquire);
000000013F931A1D prefetchw [a]
000000013F931A22 mov eax,dword ptr [a]
000000013F931A26 mov edx,eax
000000013F931A28 lock cmpxchg dword ptr [a],edx
000000013F931A2E jne main+36h (013F931A26h)
std::cout << val << "\n";
但是安东尼·威廉姆斯(Anthony Williams)说:
some_atomic.load(std::memory_order_acquire)
只是简单地执行一个简单的加载指令,而some_atomic.store(std::memory_order_release)
只是简单的存储指令。
我错了吗?在x86/x86_64处理器上,std::memory_order_acquire
的语义是否需要使用lock cmpxchg
或者只是像安东尼·威廉姆斯所说的那样,一个简单的加载指令mov
?
回答:这与此错误报告相同:http://connect.microsoft.com/VisualStudio/feedback/details/770885
volatile
早在很久以前就出现了,当时还没有关于std::memory_order
的任何了解。为了避免不必要的调用WinAPI或汇编代码,他们决定对volatile
使用屏障(lock
) - 这三种解决方案同样不美观。但是现在有了新的C++11标准,所有内容都已经明确定义,并且有一个优雅的解决方案 -mov
。也许对于旧的x86处理器需要在load()
中加锁? - Alexstd::atomic
内部使用volatile
所导致的人为/错误(我相信标准要求使用volatile
)。 - Mats Petersson