cmpxchg
,特别是PDF you are quoting from讲述了一个不同的故事。Microsoft提供了InterlockedCompareExchange
函数,用于执行原子比较和交换操作。还有一个InterlockedCompareExchange
intrinsic。
在x86上,这些是使用_InterlockedCompareExchange
指令实现的。
但是,通读有关这三种方法的文档,他们似乎在对齐要求上并不一致。
Intel的_InterlockedCompareExchange
没有对对齐进行任何说明(除了启用了[[if对齐检查并且进行了未对齐的内存引用,生成了异常)]
lock cmpxchg
前缀,它具体指出:>LOCK前缀的完整性受内存字段的对齐方式影响。[>]reference manual内在文档也没有提到对齐,但是(我的重点)
所以Intel似乎说对齐是无关紧要的。无论如何,该操作都是原子操作。
lock
function
指出此功能的参数必须在32位边界上对齐;否则,该功能在多处理器x86系统和任何非x86系统上的行为将无法预测。
那有什么作用?_InterlockedCompareExchange
的对齐要求仅仅是为了确保该功能即使在InterlockedCompareExchange
指令不可用的486之前的CPU上也能正常工作吗?基于以上信息,这似乎很可能,但是我想在确定之前先确定一下。 :)
或者ISA是否需要对齐以保证原子性,而我只是在Intel参考手册中找错了位置?
Microsoft提供用于执行原子比较和交换操作的InterlockedCompareExchange函数。还有一个_InterlockedCompareExchange内部函数。在x86上,这些是使用...
InterlockedCompareExchange
来自1999年,显然已经过时。cmpxchg
,特别是PDF you are quoting from讲述了一个不同的故事。例如,在Core-i7处理器上,您仍然必须确保数据不跨越高速缓存行,否则,不能保证操作是原子的。
关于卷3A,系统编程,对于x86 / x64英特尔明确指出:
8.1.1保证原子操作
Intel486处理器(以及更新的处理器)保证以下各项基本的内存操作将始终以原子方式执行:读取或写入字节
读取或写入在16位边界上对齐的单词
- 读取或写入在32位边界上对齐的双字
- 奔腾处理器(以及以后的较新处理器)保证以下各项其他内存操作将始终以原子方式执行:
读取或写入在64位边界上对齐的四字
16位访问适合32位数据总线的未缓存内存位置
- P6系列处理器(以及以后的较新处理器)保证以下各项额外的内存操作将始终以原子方式进行:
对适合缓存的缓存内存进行未对齐的16位,32位和64位访问行
访问跨缓存行和页面边界划分的可缓存内存Intel Core 2 Duo,Intel®Atom™,Intel Core不保证是原子的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系列处理器提供总线控制信号,允许外部存储器使分裂访问成为原子的子系统;但是,未对齐的数据访问将严重影响处理器的性能,应避免]
x86会not要求对齐才能使up-to-date Intel documentation指令是原子的。但是,为了获得良好的性能,必须进行对齐。为什么Microsoft确切说明对齐要求不清楚。支持RISC架构当然是必要的,但是多处理器x86上不可预测的行为的特定声明甚至可能无效。 (除非它们表示不可预测的性能,而不是正确性问题。)这并不奇怪,向后兼容意味着用14年前的手册编写的软件仍可以在当今的处理器上运行。现代CPU甚至有一个专门用于分割Volume-3A检测的性能计数器,因为它是如此昂贵。 (核心不能在操作期间仅保持对单个高速缓存行的独占访问;它的确必须执行类似传统总线锁定的操作)。
您猜测仅适用于没有
lock cmpxchg
的486之前的系统可能是正确的;那里需要一个不同的机制,这可能需要围绕纯负载或纯存储进行某种锁定。 (还请注意,486lock
与lock cmpxchg
有所不同,cmpxchg
(currently-undocumented opcode)与586 Pentium是新的; Windows可能仅在P5 Pentium上使用了0f a7
,但我不知道。)这也许可以解释某些x86上的怪异现象,但并不意味着现代x86上的怪异现象。[Intel®64和IA-32体系结构软件开发人员手册第3卷(3A):系统编程指南2013年1月
8.1.2.2软件控制的总线锁定要显式强制使用LOCK语义,在用于修改内存位置时,软件可以将LOCK前缀与以下说明配合使用。 [...]
•交换指令(XADD,CMPXCHG和CMPXCHG8B)。•XCHG指令自动假定为LOCK前缀。•[...]
[...]总线锁的完整性不受总线对准的影响内存字段。在多个总线周期内都遵循LOCK语义根据需要更新整个操作数。但是,建议使锁定的访问在其自然边界上对齐以更好地进行系统性能:
•8位访问的任何边界(锁定或其他)。•16位边界,用于锁定字访问。•用于锁定双字访问的32位边界。•用于锁定四字访问的64位边界。
有趣的事实:modern
cmpxchg
(0f b1
),因此可用于单核系统上的多线程。
即使未对齐,它仍然是原子的。中断(完全在中断之前或之后),并且只有其他设备(例如DMA)读取的内存才会出现中断。但是,这样的访问也可能会看到加载和存储之间的分离,因此,即使旧的Windows确实将其用于单核系统上更有效的InterlockedCompareExchange,它仍然不需要为正确性而对齐,而仅需要性能。如果可以将其用于硬件访问,则Windows可能不会这样做。如果库函数需要执行与
cmpxchg
分开的纯加载,这可能是有道理的,但不需要这样做。 (如果未内联,则32位版本必须从堆栈中加载其args,但这是私有的,不能访问共享变量。)请参阅0f b1
:自然对齐对于性能很重要,并且在x64体系结构上是必需的(因此,它不仅是PRE-x86系统,而且是POST-x86系统-x64仍然是一个小众市场,但毕竟它越来越受欢迎;-);这可能就是Microsoft按要求对其进行记录的原因(很难找到有关MS是否已决定通过启用对齐检查来强制对齐问题的文档-可能因Windows版本而异;通过在文档中声称需要对齐,MS保留了在某些版本的Windows中强制使用它的自由,即使他们没有在其他版本上强制使用它。]Microsoft的互锁API也适用于ia64(尽管它仍然存在)。 ia64上没有锁定前缀,只有cmpxchg.acq和cmpxchg.rel指令(或fetchadd和其他类似的野兽),如果我没记错的话,这些都需要对齐。
cmpxchg
,特别是PDF you are quoting from讲述了一个不同的故事。这并不奇怪,向后兼容意味着用14年前的手册编写的软件仍可以在当今的处理器上运行。现代CPU甚至有一个专门用于分割Volume-3A检测的性能计数器,因为它是如此昂贵。 (核心不能在操作期间仅保持对单个高速缓存行的独占访问;它的确必须执行类似传统总线锁定的操作)。