原子 x86 指令与 MS 的 InterlockedCompareExchange 文档的对齐要求?
Microsoft 提供 InterlockedCompareExchange
< /a> 用于执行原子比较和交换操作的函数。还有一个 _InterlockedCompareExchange
内在的。
在 x86 上,这些是使用 lock cmpxchg
指令实现的。
然而,通读这三种方法的文档,他们似乎在对齐要求上没有达成一致。
英特尔的参考手册没有提到对齐(除了如果启用了对齐检查并且进行了未对齐的内存引用,则会生成异常)
我还查找了lock前缀,它特别指出
LOCK 前缀的完整性不受内存字段对齐的影响。
(强调我的)
所以英特尔似乎说对齐是无关紧要的。无论如何,该操作都是原子的。
_InterlockedCompareExchange
内在文档也没有提及对齐,但是 InterlockedCompareExchange
function 指出
该函数的参数必须在 32 位边界上对齐;否则,该函数在多处理器 x86 系统和任何非 x86 系统上的行为将无法预测。
那么什么给出呢? InterlockedCompareExchange 的对齐要求是否只是为了确保该函数即使在 cmpxchg
指令不可用的 486 之前的 CPU 上也能正常工作? 根据上述信息,这似乎是可能的,但我想在依赖它之前确定一下。 :)
还是 ISA 需要对齐来保证原子性,而我只是在英特尔参考手册中查找了错误的位置?
Microsoft offers the InterlockedCompareExchange
function for performing atomic compare-and-swap operations. There is also an _InterlockedCompareExchange
intrinsic.
On x86 these are implemented using the lock cmpxchg
instruction.
However, reading through the documentation on these three approaches, they don't seem to agree on the alignment requirements.
Intel's reference manual says nothing about alignment (other than that if alignment checking is enabled and an unaligned memory reference is made, an exception is generated)
I also looked up the lock
prefix, which specifically states that
The integrity of the LOCK prefix is not affected by the alignment of the memory field.
(emphasis mine)
So Intel seems to say that alignment is irrelevant. The operation will be atomic no matter what.
The _InterlockedCompareExchange
intrinsic documentation also says nothing about alignment, however the InterlockedCompareExchange
function states that
The parameters for this function must be aligned on a 32-bit boundary; otherwise, the function will behave unpredictably on multiprocessor x86 systems and any non-x86 systems.
So what gives?
Are the alignment requirements for InterlockedCompareExchange
just to make sure the function will work even on pre-486 CPU's where the cmpxchg
instruction isn't available?
That seems likely based on the above information, but I'd like to be sure before I rely on it. :)
Or is alignment required by the ISA to guarantee atomicity, and I'm just looking the wrong places in Intel's reference manuals?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
x86不要求将
lock cmpxchg
指令对齐为原子指令。然而,为了获得良好的性能,对齐是必要的。这应该不足为奇,向后兼容性意味着 14 年前使用手册编写的软件仍然可以在今天的处理器上运行。现代 CPU 甚至有一个专门用于分割锁检测的性能计数器,因为它非常昂贵。 (核心不能在操作期间仅保留对单个高速缓存行的独占访问;它必须执行类似于传统总线锁定的操作)。
Microsoft 究竟为何记录对齐要求尚不清楚。这对于支持 RISC 架构当然是必要的,但多处理器 x86 上的不可预测行为的具体声明甚至可能是无效的。 (除非它们意味着不可预测的性能,而不是正确性问题。)
您对仅适用于没有
lock cmpxchg
的 486 之前的系统的猜测可能是正确的;那里需要一种不同的机制,这可能需要某种围绕纯加载或纯存储的锁定。 (另请注意,486cmpxchg
有一个不同的当前未记录的操作码 (0f a7
) 来自 现代cmpxchg
(< code>0f b1) 这是 586 Pentium 的新功能;Windows 可能只在 P5 Pentium 及更高版本上使用cmpxchg
,我不知道。)这也许可以解释某些 x86 上的怪异,并不意味着现代 x86 上的怪异。有趣的事实:
cmpxchg
没有lock
前缀仍然是原子的。上下文切换,因此可用于单核系统上的多线程。即使未对齐,它仍然是原子的。中断(完全在之前或完全在之后),并且只有其他设备(例如 DMA)的内存读取才能看到撕裂。但此类访问也可以看到加载和存储之间的分离,因此即使旧 Windows 确实在单核系统上使用它来实现更高效的 InterlockedCompareExchange,它仍然不需要正确性对齐,只需要性能对齐。如果这可以用于硬件访问,Windows 可能不会这样做。
如果库函数需要执行与锁定 cmpxchg 分开的纯加载,这可能有意义,但不需要这样做。 (如果不是内联的,32 位版本必须从堆栈加载其参数,但这是私有的,不能访问共享变量。)
x86 does not require alignment for a
lock cmpxchg
instruction to be atomic. However, alignment is necessary for good performance.This should be no surprise, backward compatibility means that software written with a manual from 14 years ago will still run on today's processors. Modern CPUs even have a performance counter specifically for split-
lock
detection because it's so expensive. (The core can't just hold onto exclusive access to a single cache line for the duration of the operation; it does have to do something like a traditional bus lock).Why exactly Microsoft documents an alignment requirement is not clear. It's certainly necessary for supporting RISC architectures, but the specific claim of unpredictable behaviour on multiprocessor x86 might not even be valid. (Unless they mean unpredictable performance, rather than a correctness problem.)
Your guess of applying only to pre-486 systems without
lock cmpxchg
might be right; a different mechanism would be needed there which might have required some kind of locking around pure loads or pure stores. (Also note that 486cmpxchg
has a different and currently-undocumented opcode (0f a7
) from moderncmpxchg
(0f b1
) which was new with 586 Pentium; Windows might have only usedcmpxchg
on P5 Pentium and later, I don't know.) That could maybe explain weirdness on some x86, without implying weirdness on modern x86.Fun fact:
cmpxchg
without alock
prefix is still atomic wrt. context switches, so is usable for multi-threading on a single-core system.Even misaligned it's still atomic wrt. interrupts (either completely before or completely after), and only memory reads by other devices (e.g. DMA) could see tearing. But such accesses could also see the separation between load and store, so even if old Windows did use that for a more efficient InterlockedCompareExchange on single-core systems, it still wouldn't require alignment for correctness, only performance. If this can be used for hardware access, Windows probably wouldn't do that.
If the library function needed to do a pure load separate from the
lock cmpxchg
this might make sense, but it doesn't need to do that. (If not inlined, the 32-bit version would have to load its args from the stack, but that's private, not access to the shared variable.)您引用的 PDF 是 1999 年的,显然已经过时了。
最新英特尔文档,特别是Volume-3A 讲述了一个不同的故事。
例如,在 Core-i7 处理器上,您仍然必须确保数据不会跨越缓存行,否则不能保证操作是原子的。
在第 3A 卷“系统编程,针对 x86/x64”中,英特尔明确指出:
The PDF you are quoting from is from 1999 and CLEARLY outdated.
The up-to-date Intel documentation, specifically Volume-3A tells a different story.
For example, on a Core-i7 processor, you STILL have to make sure your data doesn't not span over cache-lines, or else the operation is NOT guaranteed to be atomic.
On Volume 3A, System Programming, For x86/x64 Intel clearly states:
请参阅这个SO问题:自然对齐对于性能很重要,并且在x64架构上是必需的(因此,不仅是 PRE-x86 系统,还包括 POST-x86 系统 —— x64 可能仍然是一个小众案例,但它毕竟越来越受欢迎;-);这可能就是为什么微软按要求记录它(很难找到关于微软是否决定通过启用对齐检查来强制对齐问题的文档——这可能因Windows版本而异;通过在文档中声明需要对齐,微软保留了可以自由地在某些版本的 Windows 中强制执行此操作,即使他们没有在其他版本中强制执行此操作)。
See this SO question: natural alignment is important for performance, and is required on the x64 architecture (so it's not just PRE-x86 systems, but POST-x86 ones too -- x64 may still be a bit of a niche case but it's growing in popularity after all;-); that may be why Microsoft documents it as required (hard to find docs on whether MS has decided to FORCE the alignment issue by enabling alignment checking -- that may vary by Windows version; by claiming in the docs that alignment is required, MS keeps the freedom to force it in some version of Windows even if they did not force it on others).
Microsoft 的 Interlocked API 也适用于 ia64(当它仍然存在时)。 ia64 上没有锁前缀,只有 cmpxchg.acq 和 cmpxchg.rel 指令(或 fetchadd 和其他类似的东西),如果我没记错的话,这些都需要对齐。
Microsoft's Interlocked APIs also applied to ia64 (while it still existed). There was no lock prefix on ia64, only the cmpxchg.acq and cmpxchg.rel instructions (or fetchadd and other similar beasties), and these all required alignment if I recall correctly.