我对 x86 上的顺序一致的加载操作很感兴趣。
据我从汇编程序列表中看到的,由编译器生成它是作为 x86 上的普通加载实现的,但是据我所知,普通加载保证具有获取语义,而普通存储保证具有释放。
顺序一致的存储实现为锁定的 xchg,而加载为普通加载。这听起来很奇怪,你能详细解释一下吗?
添加
刚刚在互联网上发现,只要使用锁定的 xchg 完成存储,就可以像简单的 mov 一样完成顺序一致的原子加载,但是没有证据,也没有文档链接。
我对 x86 上的顺序一致的加载操作很感兴趣。
据我从汇编程序列表中看到的,由编译器生成它是作为 x86 上的普通加载实现的,但是据我所知,普通加载保证具有获取语义,而普通存储保证具有释放。
顺序一致的存储实现为锁定的 xchg,而加载为普通加载。这听起来很奇怪,你能详细解释一下吗?
添加
刚刚在互联网上发现,只要使用锁定的 xchg 完成存储,就可以像简单的 mov 一样完成顺序一致的原子加载,但是没有证据,也没有文档链接。
x86 上的 plainMOV
对于原子顺序一致的加载就足够了,只要 SC 存储使用LOCK
ed 指令完成,值正确对齐,并且使用“正常”WB缓存模式。
有关完整映射,请参阅我在http://www.justsoftwaresolutions.co.uk/threading/intel-memory-ordering-and-c++-memory-model.html上的博客文章,以及在http://developer上的英特尔处理器文档.intel.com/products/processor/manuals/index.htm了解允许订购的详细信息。
如果您使用“WC”缓存模式或“非临时”指令,MOVNTI
那么所有的赌注都将被取消,因为处理器不一定会及时将数据写回主存。
x86 上的读取本质上是原子的,只要它们对齐,MOV
intel assembly manuals vol 2A 中的说明下的部分应该提到这一点,与LOCK
前缀相同。其他卷也可能提到这一点
但是,如果你想要一个atomic read
,你可以使用_InterlockedExchangeAdd((LONG*)&var,0)
aka LOCK XADD
,这将产生旧值,但不会改变它的值,同样可以用InterlockCompareExchange((LONG*)&var,var,var)
aka完成LOCK CMPXCHG
,但是 IMO,不需要这个
寄存器到内存的传输(反之亦然)在多处理器环境中不一定是原子的。
阅读
XOR EAX, EAX
LOCK XADD [address], EAX
第一条指令将 EAX 寄存器归零,第二条指令将两个 EAX 的内容与 [address] 交换,并将两者的总和再次存储在 [address] 中。由于之前 EAX 寄存器为零,因此没有任何变化。
写作
XCHG [address], EAX
EAX 寄存器将获取值存储到指定地址。
编辑: LOCK ADD EAX, [address] 将导致“无效操作码异常”,因为目标操作数不是内存地址。
当 LOCK 前缀与任何其他指令一起使用或未对内存进行写操作时,将生成无效操作码异常 (#UD)。8.1.2.2 软件控制的总线锁定
编辑 2:总结评论中的信息。
尽管
“[...] 处理器的锁定协议在交换操作期间自动实现,无论是否存在 LOCK 前缀或 IOPL 的值。”
对此有限制
“对跨总线宽度、缓存行和页面边界的可缓存内存的访问不能保证是原子的”