Assembly 如何以原子方式读取x86 ASM中的值?

Assembly 如何以原子方式读取x86 ASM中的值?,assembly,x86,thread-safety,atomic,Assembly,X86,Thread Safety,Atomic,我知道如何在x86 ASM中自动写入值。但是我怎么读呢?锁定前缀不能与mov一起使用 要增加值,我正在执行以下操作: lock inc dword ptr Counter 如何以线程安全的方式读取计数器?我不是汇编专家,但字大小(在x86上,32位)的读取/写入应该已经是原子的了 您需要锁定增量的原因是因为它既是读取又是写入。对于简单的读取,主要是关于对齐。确保原子读取的最简单方法是始终使用“自然”对齐方式,即对齐方式至少与项目大小相同(例如,32位项目是32位对齐的) 未对齐的读取不一定是原

我知道如何在x86 ASM中自动写入值。但是我怎么读呢?锁定前缀不能与mov一起使用

要增加值,我正在执行以下操作:

lock inc dword ptr Counter

如何以线程安全的方式读取计数器?

我不是汇编专家,但字大小(在x86上,32位)的读取/写入应该已经是原子的了


您需要锁定增量的原因是因为它既是读取又是写入。

对于简单的读取,主要是关于对齐。确保原子读取的最简单方法是始终使用“自然”对齐方式,即对齐方式至少与项目大小相同(例如,32位项目是32位对齐的)

未对齐的读取不一定是原子的。对于一个极端的例子,考虑在一个奇数地址读取一个32位值,其中第一个字节在一个高速缓存行中,另外三个字节在另一个高速缓存行中。在这种情况下,原子读取基本上是不可能的

由于(至少大多数)处理器使用64位宽的内存总线,因此希望以原子方式读取的最大项是64位。

正如我在文章中向您解释的:

对可缓存内存的访问 跨总线宽度、缓存线拆分, 而且页面边界也不能保证 由Intel Core 2 Duo打造原子级, 英特尔酷睿双核、奔腾M、奔腾4、, 英特尔至强、P6系列、奔腾和 Intel486处理器。英特尔核心2 Duo,Intel Core Duo,奔腾M, 奔腾4、英特尔至强和P6系列 处理器提供总线控制信号 允许外部内存子系统 使分裂访问原子化; 但是,不对齐的数据访问将 严重影响公司的业绩 应避免使用处理器和

因此,请使用:

LOCK        CMPXCHG   EAX, [J]
锁定CMPXCHG first fence缓存,然后将EAX与目标值进行比较,如果目标值不相等,则EAX中的结果为目标值

编辑: 链接至:

检查第8.1.1节


同时检查:

阅读其他回复很有趣。我想@GJ可能是在花钱

多年来,32位读写一直是原子的。直到最近几年,真正具有攻击性的缓存才不再保证这一点


我想这就是为什么我喜欢C++,java或者我和机器代码之间的一些。如今,机器代码太复杂,无法可靠地编写(除非你经常这样做以保持你的技能)。幸运的是,今天的优化编译器非常好,您很少需要手动优化汇编程序的性能。

不一定!如果内存地址在使用多CPU单元中的第二个CPU的高速缓存中,则不能保证读取是原子的。因此,请使用“LOCK CMPXCHG EAX,[var]”作为第一道栅栏内存缓存。@GJ:我认为这只适用于未对齐的数据-通常情况下,您不会有未对齐的数据,所以这不应该是一个问题?我知道读取不会是原子的,但它仍然是一个快照,这意味着该值肯定是正确的?即使您有2个CPU,并且它们的缓存正在同步,我认为锁在确保值在读取var之前是最新的方面也不会起任何作用。。。或者会吗?@Paul R:如果两个线程在某个时间运行,每个线程在自己的CPU下访问某个内存地址,则不会出现这种情况。在这种情况下,需要缓存同步。有些指令,如“LOCK CMPXCHG”,会自动执行此操作。像MOV这样的指令需要第一条内存围栏指令来同步缓存内存。检查:英特尔®64和IA-32体系结构软件开发人员手册。我已经在我的答案中添加了链接。@GJ.:
mov
load/store是原子的,如果地址是对齐的。x86具有一致的缓存,因此即使多个CPU读取/写入同一位置,。也不会编译,因为[J]是内存指针。它必须是一个寄存器值。这是我无法回避的第22条军规。我从你的另一篇文章中看到,只要值与CPU的总线宽度对齐,这实际上不是问题。@IamIC:确切地说,不是总线宽度。英特尔和AMD保证的最低公分母是
mov
load/store是原子的,或者是未缓存的,如果是对齐的,或者是不跨越dword边界的16位访问。另外,
[J]
只是一种绝对或(在x86-64中)RIP相对寻址模式。这不是双重间接。它装配得很好。MASM语法通常会忽略
[]
,但它们在MASM中是可选的,在NASM中是必需的。无论如何,由于错误地暗示您需要
锁定cmpxchg
,因此被否决。在静态数据上,在 J:< /Cord>标签之前简单使用<代码> 4 。我暗示了什么?C++将不能保证任何内存语义高于CPU所做的事情,也不会保证java没有波动。C++可以保证原子类型(C++ 11的东西)的原子访问,如C(C11)。