Microsoft提供InterlockedCompareExchange
函数来执行原子比较和交换操作。还有一个_InterlockedCompareExchange
内在。
在x86上,这些是使用cmpxchg
指令实现的。
但是,通过阅读这三种方法的文档,他们似乎并不同意对齐要求。
英特尔reference manual没有提及对齐(除了,如果对齐检查已启用且未对齐的内存引用,则会生成异常)
我还查找了lock
前缀,该前缀明确指出
LOCK前缀的完整性不受内存字段对齐的影响。
(强调我的)
所以英特尔似乎认为对齐无关紧要。无论如何,这个操作都是原子的。
_InterlockedCompareExchange
内在文档也没有说明对齐,但InterlockedCompareExchange
函数表明
此函数的参数必须在32位边界上对齐;否则,该函数将在多处理器x86系统和任何非x86系统上表现不可预测。
那是什么给出的?
InterlockedCompareExchange
的对齐要求是否只是为了确保该函数即使在没有cmpxchg
指令的486之前的CPU上也能正常工作?
这看起来可能基于上述信息,但在依赖它之前我想确定一下。 :)
或者ISA是否需要对齐来保证原子性,我只是在英特尔的参考手册中找错了地方?
答案 0 :(得分:10)
PDF you are quoting from来自1999年,已经过时了。
up-to-date Intel documentation,特别是Volume-3A讲述了另一个故事。
例如,在Core-i7处理器上,您仍然必须确保您的数据不会跨越缓存行,否则操作不能保证是原子的。
在第3A卷,系统编程,对于x86 / x64,英特尔明确指出:
8.1.1保证原子操作
Intel486处理器(以及更新的处理器)保证以下内容 基本的内存操作将始终以原子方式执行:
- 读取或写入字节
- 读取或写入在16位边界上对齐的字
- 读取或写入在32位边界上对齐的双字
Pentium处理器(以及更新的处理器)保证以下内容 额外的内存操作将始终以原子方式执行:
- 读取或写入在64位边界上对齐的四字
- 16位访问适合32位数据总线的未缓存内存位置
P6系列处理器(以及更新的处理器)保证以下内容 额外的内存操作将始终以原子方式执行:
- 对缓存中适合的高速缓存内存的16位,32位和64位未对齐访问 线
访问可缓存内存,这些内存分为缓存行和页面边界 英特尔酷睿2双核,英特尔®凌动™,英特尔酷睿不保证是原子的 Duo,Pentium M,Pentium 4,Intel Xeon,P6系列,Pentium和Intel486处理器。 Intel Core 2 Duo,Intel Atom,Intel Core Duo,Pentium M,Pentium 4,Intel Xeon, 和P6系列处理器提供允许外部存储器的总线控制信号 子系统使分裂访问成为原子;但是,非对齐数据访问将会 严重影响处理器的性能,应该避免
答案 1 :(得分:10)
x86 不需要cmpxchg
指令的对齐方式。但是,建议使用对齐以提高性能。这应该不足为奇,向后兼容意味着用14年前的手册编写的软件仍然可以在今天的处理器上运行。
为什么Microsoft要求对齐并不清楚他们的文档。它可能用于性能或支持RISC架构,或两者兼而有之。
英特尔®64和IA-32架构软件开发人员手册
第3卷(3A):系统编程指南
2013年1月8.1.2.2软件控制总线锁定
要明确强制LOCK语义,软件可以在使用LOCK前缀时使用以下说明来修改内存位置。 [...]
•交换指令(XADD,CMPXCHG和CMPXCHG8B) •XCHG指令自动采用LOCK前缀 •[...]
[...]总线锁的完整性不受对齐的影响 记忆领域。遵循LOCK语义的总线周期数 必要时更新整个操作数。但是,建议 锁定的访问在其自然边界上对齐以获得更好的效果 系统性能:
•8位访问的任何边界(锁定或其他) •锁定字访问的16位边界 •锁定双字访问的32位边界 •锁定四字访问的64位边界。
答案 2 :(得分:5)
请参阅this SO question:自然对齐对于性能很重要,并且在x64架构上是必需的(因此它不仅仅是PRE-x86系统,而是POST-x86系统 - x64可能仍然有点像利基案例,但它毕竟越来越受欢迎;-);这可能就是微软根据需要对其进行记录的原因(很难找到有关MS是否决定通过启用对齐检查来解决对齐问题的文档 - 这可能因Windows版本而异;通过在文档中声明需要对齐,MS保留了在某些版本的Windows中强制它的自由,即使它们没有强迫它在其他版本中。)
答案 3 :(得分:3)
微软的Interlocked API也适用于ia64(虽然它仍然存在)。 ia64上没有锁定前缀,只有cmpxchg.acq和cmpxchg.rel指令(或者是fetchadd和其他类似的beasties),如果我没记错的话,这些都需要对齐。