只是想知道哪些CPU架构支持比较和交换原子基元?
答案 0 :(得分:10)
Powerpc有更强大的原语:“lwarx”和“stwcx”
lwarx从内存加载一个值,但会记住该位置。触及该位置的任何其他线程或CPU将导致条件存储指令“stwcx”失败。
所以lwarx / stwcx组合允许你实现原子递增/递减,比较和交换,以及更强大的原子操作,如“原子增量循环缓冲区索引”
答案 1 :(得分:8)
回答这个问题的另一种更简单的方法可能是列出不支持比较和交换的多处理器平台(或者可以用来编写一个的加载链接/存储条件)。
我所知道的唯一一个是PARISC,它只有一个原子清晰的单词指令。这可以用于构造互斥体(假设一个16字节边界上的字对齐)。这个结构上没有CAS(与x86,ia64,ppc,sparc,mips,s390,...不同)
答案 2 :(得分:7)
有些人评论/询问x86 / x64上cmpxchg是否需要“lock”前缀。多核机器的答案是肯定的。对于没有锁定的单核机器,该指令完全是原子的。
我已经有一段时间了,因为我深入研究了这些东西,但我似乎记得该指令在技术上是可重启的 - 它可以在飞行途中中止指令(如果它还没有任何副作用),以避免延迟中断处理时间过长。
答案 3 :(得分:5)
Intel x86有此支持。 IBM中的Solaris to Linux Porting Guide给出了这个例子:
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;
}
答案 4 :(得分:5)
从ARMv6架构开始,ARM具有LDREX / STREX指令,可用于实现原子比较交换操作。
答案 5 :(得分:5)
很抱歉很多信件。 :(
x86 ISA中的几乎所有指令(除了所谓的字符串指令,可能还有其他几个),包括CMPXCHG,在unicore CPU的上下文中都是原子的。这是因为根据x86架构,CPU在每次指令执行完成后检查到达的中断,而不是在中间。结果,可以检测到中断请求,并且仅在两个连续指令的执行之间的边界上启动它的处理。由于这一点,CPU在执行单个指令期间所采用的所有存储器引用都是隔离的,并且不能通过任何其他活动进行交错。这种行为对于unicore和多核CPU来说很常见。但是,如果在单向CPU的上下文中,系统中只有一个单元执行对存储器的访问,则在多核CPU的上下文中,系统中有多于一个单元同时执行对存储器的访问。指令隔离不足以在这种环境中保持一致性,因为不同CPU在同一时间进行的存储器访问可以相互交错。由于此附加保护层必须应用于数据更改协议。对于x86,该层是锁定前缀,用于在系统总线上启动原子事务。
总结:使用没有锁定前缀的CMPXCHG,XADD,BTS等同步指令是安全且成本较低的,如果您确信,该指令访问的数据只能由一个内核访问。如果您对此不予以保证,请应用锁定前缀以通过权衡性能来提供安全性。
CPU支持硬件同步有两种主要方法:
没有人是银弹。这两种方法都有其优点和缺点。
基于原子事务的方法依赖于支持内存总线上的特殊类型的事务。在此类事务期间,只有一个连接到总线的代理(CPU核心)才有资格访问内存。结果,一方面,在原子事务处理期间由总线所有者进行的所有存储器引用被确保为单个不可中断事务。另一方面,将强制执行所有其他总线代理(CPU内核)以等待原子事务完成,以恢复访问内存的能力。即使他们想要访问原子事务期间未被总线所有者引用的内存区域,他们想要访问哪些内存单元也无关紧要。因此,大量使用锁定前缀指令会显着降低系统速度。另一方面,由于总线仲裁器根据循环调度为每个总线代理提供对总线的访问,因此可以保证每个总线代理具有相对公平的存储器访问权限,并且所有代理将是能够以同样的速度取得进步并取得进展。此外,ABA问题在原子事务的情况下发挥作用,因为其本质上,原子事务非常短(由单个指令产生的内存引用很少)并且在事务期间对内存采取的所有动作仅依赖于存储区域的值在没有考虑到帐户的情况下,两个事务之间的其他人访问了内存区域。 基于原子事务的同步支持的一个很好的例子是x86架构,其中锁定前缀指令强制CPU在原子事务中执行它们。
基于高速缓存一致性协议的方法依赖于以下事实:存储器行可以在一个时刻仅在一个L1高速缓存中被高速缓存。高速缓存一致性系统中的内存访问协议类似于下一步操作序列:
感谢协议CPU核心始终访问内存中的实际数据,并且严格按顺序序列化对内存的访问,及时访问。 基于高速缓存一致性协议的同步支持依赖于CPU可以容易地检测到在两个时间点之间访问特定存储器行的事实。在第一次访问必须打开事务的行X的内存期间,CPU可以标记L1缓存中的内存行必须由snooping agent控制。另外,snooping代理可以在缓存行刷新期间执行检查以识别该行是否标记为控制,并且如果受控行刷新则引发内部标志。因此,如果CPU在关闭事务的内存访问期间检查内部标志,它将知道受控内存行是否能够由其他人更改并且结论是事务必须成功完成或必须被视为失败。 这是LL \ SC指令类实现的方式。这种方法比原子事务更简单,并且在同步中提供了更大的灵活性,因为与原子事务方法相比,可以在其上构建更多数量的不同同步原语。这种方法更具可扩展性和效率,因为它不会阻止对系统所有其他部分的内存访问。正如您所看到的,它解决了ABA问题,因为它基于内存区域访问检测的事实,而不是内存区域更改检测的值。对参与正在进行的事务的存储器区域的任何访问都将被视为事务失败。这可能是好的和坏的同时,因为特定的算法只能对内存区域的价值感兴趣,并且不会在帐户中占用该位置是由中间人访问的,直到该访问更改为止记忆。在这种情况下,读取中间的内存值将导致错误的否定事务失败。此外,这种方法可能导致控制流在同一存储器线上的性能大幅下降,因为它们能够不断地相互记忆存储线,并且通过这种方式防止彼此成功完成交易。这是一个非常重要的问题,因为在终端案例中它可以在活锁中转换系统。 基于缓存一致性协议的同步支持通常用于RISC CPU,因为它简单灵活。但必须指出的是,英特尔也决定在x86架构中支持这种同步支持方法。去年,英特尔发布了针对x86架构的事务同步扩展,该架构将在Haswell一代英特尔处理器中实施。结果,看起来,x86将拥有最强大的同步支持,并允许系统开发人员利用这两种方法的优势。
答案 6 :(得分:4)
为了完成列表,MIPS具有Load Linked(ll)和Store Conditional(sc)指令,这些指令从内存加载值,如果没有其他CPU访问该位置,则稍后有条件地存储。您可以使用这些指令执行交换,增量和其他操作。然而,缺点是,由于大量的CPU会非常严重地执行锁定,因此您会遇到活锁:条件存储将经常失败并需要再次尝试另一个循环,这将失败等等。
如果认为这些情况足够重要,那么软件mutex_lock实现可能会变得非常复杂,试图实现指数退避。在一个系统中我使用了128个内核,它们是。
答案 7 :(得分:3)
x86和Itanium具有CMPXCHG(比较和交换)
答案 8 :(得分:3)
1973年,比较和交换被添加到IBM大型机。它(并且比较双重和交换)仍然在IBM大型机上(以及更新的多处理器功能,如PLO - 执行锁定操作)。
答案 9 :(得分:2)
Sparc v9有一条cas指令。 SPARC v9 architecture manual讨论了附件J中CAS指令的使用,具体见J.11和J.12示例。
我相信指令的名称实际上是“casa”,因为它可以访问当前地址空间或备用地址。 “cas”是一个访问当前ASI的汇编器宏。
还有一篇文章developers.sun.com讨论了Sparc处理器多年来实施的各种原子指令,包括cas。