如何自动读取x86 ASM中的值?

问题描述:

我知道如何在x86 ASM中原子地写入一个值。但是我怎么读一个? LOCK前缀不能与mov一起使用。如何自动读取x86 ASM中的值?

要增加的值,我做:

lock inc dword ptr Counter 

如何在一个线程安全的方式读取计数器?

我不是装配专家,但字大小(在x86,32位)读/写应该是原子已经。

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

+0

我认为你是对的。这就说得通了。谢谢。 – IamIC 2010-07-28 04:12:46

+0

不要忘了接受一个答案,如果它帮助你;) – 2010-07-28 04:20:12

+4

并不总是!如果内存地址在使用多CPU单元中的第二个CPU的高速缓存中,则读数不保证是原子的。因此,使用“LOCK CMPXCHG EAX,[var]”,它首先围绕内存缓存。 – 2010-07-28 06:03:58

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

未对齐的读取不一定是原子。举一个极端的例子,考虑在第一个字节在一个缓存行中的奇数地址处读取一个32位值,其他三个字节在另一个缓存行中。在这种情况下,原子读取基本上是不可能的。由于(至少大多数)处理器使用64位宽的存储器总线,所以希望被原子读取的最大项目是64位。

正如我在this后向你解释:

访问缓存的内存是跨越总线带宽,高速缓存行, 和页面边界,不能保证 由英特尔酷睿2是原子 分裂Duo, Intel Core Duo,Pentium M,Pentium 4, Intel Xeon,P6系列,Pentium和 Intel486处理器。 Intel Core 2 Duo,Intel Core Duo,Pentium M, Pentium 4,Intel Xeon和P6系列处理器提供总线控制信号 ,允许外部存储器子系统 使分割访问原子化;然而,非对齐的数据访问将会严重影响处理器的性能,应该避免。

所以使用:

LOCK  CMPXCHG EAX, [J] 

LOCK CMPXCHG第一栅栏高速缓冲存储器和比比较目标值的EAX,如果目标值不EQU那么结果在EAX是目标值。

编辑: 链接:

Intel® 64 and IA-32 Architectures Software Developer’s Manuals

Volume 3A: System Programming Guide检查8.1.1节

同时检查:Optimization Reference Manual section: CHAPTER 7 OPTIMIZING CACHE USAGE

+0

因为[J]是内存指针,所以不会编译。它必须是一个注册值。这是我无法解决的问题。 – IamIC 2010-07-28 15:40:52

+1

我从你的另一篇文章中看到,只要值与CPU的总线宽度一致,这实际上不是问题。 – IamIC 2010-07-28 15:53:07

+0

@IamIC:完全不是总线宽度。英特尔和AMD保证的最低公分母是'mov'加载/存储是原子的(如果它不跨越8字节边界(对于缓存访问)。](https://*.com/a/36685056/224132)或者对于未缓存的,如果对齐或者不跨越双字边界的16位访问。另外'[J]'是一个绝对的或(在x86-64中)一个RIP相对寻址模式。这不是双重间接。它组装得很好。 MASM语法通常会忽略'[]',但它们在MASM中是可选的,并且在NASM中是必需的。 – 2018-01-01 01:42:18

有趣的是,阅读对方回复。我认为@GJ可能就是这笔钱。

多年来,32位读写是原子总是如此。只有在最近几年,真正积极的缓存才能保证这一点。

我想这就是为什么我更喜欢C++,Java或其他类似于我和机器代码之间的原因。这些天机器代码太复杂,无法可靠地写入(除非你这样做)。很多保持你的技能锐利)。幸运的是,今天的优化编译器非常好,所以你很少需要手动优化汇编器的性能。

+0

C++不会保证有关CPU的内存语义的任何内容,也不会保证Java没有volatile。 – 2012-08-27 07:46:55

+0

与C(C11)一样,C++可以保证原子类型(C++ 11的东西)的原子访问。 – 2014-06-03 13:51:48