只是好奇想知道哪些CPU架构支持比较和交换原语?
只是好奇想知道哪些CPU架构支持比较和交换原语?
Powerpc拥有更强大的原语可用: "lwarx"和"stwcx"
lwarx从内存加载一个值但记住位置。任何其他线程或CPU触及该位置将导致"stwcx"(条件存储指令)失败。
因此,lwarx / stwcx组合允许您实现原子递增/递减、比较和交换以及更强大的原子操作,如"原子递增循环缓冲区索引"。
很抱歉,这里有很多字母。:(
x86指令集中的几乎所有指令(除了所谓的字符串指令和可能还有其他一些指令)在unicore CPU的上下文中都是原子性的。这是因为按照x86架构的规定,在每个指令执行完成后CPU会检查是否有中断到达,并且永远不会在中途检查。因此,只有在执行两个连续指令之间的边界时才可以检测到中断请求并启动处理。由于这种行为对于单核和多核CPU都是普遍的,因此CPU在执行单个指令期间获取的所有内存引用都是被隔离的,并且无法与任何其他活动交错。但是,如果在unicore CPU的上下文中只有系统的一个单元执行对内存的访问,那么在multicore CPU的上下文中就有多个系统单元同时执行对内存的访问。在这种环境中,指令隔离是不足以保证一致性的,因为在同一时间内由不同CPU进行的内存访问可能会交错。因此,必须对数据更改协议应用附加的保护层。对于x86而言,这个层是lock前缀,它在系统总线上发起原子事务。
总结:如果您确信此指令访问的数据只能由一个核心访问,则使用无lock前缀的同步指令(如CMPXCHG、XADD、BTS等)是安全且成本较低的。如果您对此不确定,则应用lock前缀来提供安全性,以换取性能。
CPU支持硬件同步的两种主要方法:
没有银弹。这两种方法都有其优点和缺点。
基于原子事务的方法依赖于内存总线上特殊类型的事务支持。在这种事务期间,只有连接到总线的一个代理(CPU核心)有资格访问内存。结果是,在一方面,由总线所有者在原子事务期间进行的所有内存引用都保证作为单个不可中断的事务进行。另一方面,所有其他总线代理(CPU核心)都将被强制等待原子事务完成,以恢复访问内存的能力。无论他们想要访问哪些内存单元,即使他们想要访问在原子事务期间没有被总线所有者引用的内存区域。因此,广泛使用lock前缀指令会显著减慢系统的速度。另一方面,由于总线仲裁器根据轮廓调度为每个总线代理提供对总线的访问,因此保证了每个总线代理将相对公平地访问内存,并且所有代理都能够以相同的速度取得进展。此外,在原子事务的情况下,ABA问题成为其中的一部分,因为由于其本质,原子事务非常短(单个指令进行的少量内存引用),并且事务期间对内存所采取的所有操作仅依赖于内存区域的值,而不考虑在两个事务之间是否由其他人访问了该内存区域。由于该协议,CPU核总是访问内存中的实际数据,并且对内存的访问按严格顺序进行串行化,一次只能访问一个。基于缓存一致性协议的同步支持依赖于这样一个事实,即CPU可以轻松地检测到在两个时间点之间访问了特定的内存行。在第一次访问X行内存时,必须打开交易,CPU可以标记L1缓存中的内存行必须由嗅探代理控制。反过来,嗅探代理可以在缓存行刷新期间执行检查,以确定该行是否已标记为受控,并在控制行刷新时提高内部标志。结果,如果CPU在关闭事务的内存访问期间检查内部标志,它将知道受控内存行是否能够被其他人更改,并得出交易必须成功完成或必须视为失败的结论。这是LL\SC指令类实现的方式。与原子事务相比,这种方法更简单,并且在同步方面提供了更多的灵活性,因为可以基于此构建更多不同的同步原语。这种方法更具可伸缩性和效率,因为它不会阻塞其他系统部件对内存的访问。并且正如您所看到的,它解决了ABA问题,因为它基于内存区域访问检测的事实,而不是内存区域变化检测的值。任何参与正在进行的事务的内存区域的访问都将被视为交易失败。这既有好处也有坏处,因为特定算法可能仅关心内存区域的值,并且不考虑该位置是否被某个人在中间访问过,直到该访问改变了内存。在这种情况下,对内存值的读取将导致假负事务失败。此外,这种方法可能会导致控制流程的巨大性能降低,这些控制流程争夺同一内存行,并且通过这种方式相互阻止完成交易成功。这是一个非常重要的问题,因为在极端情况下,它可能会使系统处于死锁状态。缓存一致性协议基于同步支持通常用于RISC CPU,因为它简单而灵活。但必须注意的是,英特尔决定支持x86体
回答这个问题的另一种更简单的方法可能是列出不支持比较和交换(或可用于编写比较和交换的加载-链接/存储条件)的多处理器平台。
我知道的唯一一个是PARISC,它只有一个原子清除字指令。这可以用于构建互斥锁(前提是将字对齐到16字节边界)。这个架构上没有CAS(与x86、ia64、ppc、sparc、mips、s390等不同)。
从ARMv6架构开始,ARM具有LDREX / STREX指令,可用于实现原子比较交换操作。
英特尔x86平台支持此功能。IBM在其《Solaris到Linux移植指南》中给出了以下示例:
bool_t My_CompareAndSwap(IN int *ptr, IN int old, IN int new)
{
unsigned char ret;
/* Note that sete sets a 'byte' not the word */
__asm__ __volatile__ (
" lock\n"
" cmpxchgl %2,%1\n"
" sete %0\n"
: "=q" (ret), "=m" (*ptr)
: "r" (new), "m" (*ptr), "a" (old)
: "memory");
return ret;
}
lock
指令?cmpxchg
本身是原子性的吗?上面的代码只涉及一个内存位置,还是实现了内存栅栏并触发全局缓存一致性协议? - axel22比较并交换(Compare and swap)于1973年被添加到IBM大型机中。它(以及比较双精度和交换)仍然存在于IBM大型机上(以及更近期的多处理器函数,如PLO-执行锁定操作)。
x86和Itanium都具有CMPXCHG(比较和交换)指令。