C++ x86cpu上的比较与交换

C++ x86cpu上的比较与交换,c++,multithreading,cas,lock-free,C++,Multithreading,Cas,Lock Free,例如,在intel i3、i5、i7 x86 64位cpu上,CAS是否只保证最大8字节对象大小的原子 在x86 cpu上,将lock指令添加到CAS操作中,例如,CMPXCHG,这意味着整个缓存线对于读取cpu是锁定的,因此std::atomic::compare\u exchange\u weak()不会因虚假故障原因返回故障 如果x86 cpu在CAS操作时使用lock,如果在共享资源上使用无锁编程而不是std::mutex,性能会有什么提高 例如,如果我想写一个无锁链表。我在头节点的指针

例如,在intel i3、i5、i7 x86 64位cpu上,CAS是否只保证最大8字节对象大小的原子

在x86 cpu上,将lock指令添加到CAS操作中,例如,
CMPXCHG
,这意味着整个缓存线对于读取cpu是锁定的,因此
std::atomic::compare\u exchange\u weak()
不会因虚假故障原因返回故障

如果x86 cpu在CAS操作时使用
lock
,如果在共享资源上使用无锁编程而不是std::mutex,性能会有什么提高


例如,如果我想写一个无锁链表。我在头节点的指针上执行原子加载,并将其与
std::atomic::compare\u exchange\u弱()
进行比较,以查看是否进行了任何更改。在这种情况下,ABA问题是否适用于x86 cpu?

这里有几个问题:-)

  • 根据定义,CAS操作始终是原子的。话虽如此,支持什么(如果有的话)CAS操作取决于您的硬件,包括可以为此类操作交换的最大字节数。一些CPU(如ARM)根本不直接支持CAS。x86-64 CPU支持8字节CA,所有现代CPU也通过
    CMPXCHG16b
    指令支持16字节CA(通常称为双宽度CA)

  • 我不确定CAS是否会在您提到的CPU上出现错误故障(尽管我知道在某些平台上不会)。我对这些特定CPU上的缓存体系结构了解不够。然而,当在
    比较交换弱
    比较交换强
    之间进行选择时,底层硬件实现是不相关的:如果您只是在编写一个典型的小型CAS循环,那么应该使用一个对您正在做的事情有意义的弱交换(对于虚假故障的额外工作可以忽略不计),以及一个强大的交换。这也使您的代码更具可移植性和健壮性

  • 你需要衡量。这几乎完全取决于你的应用程序在做什么(如果你的应用程序真的被围绕共享资源的极高争用率所束缚,它可能会从重新设计中受益,而重新设计首先需要更少的共享)。一般来说,
    std::mutex
    是“足够好的”(实际上大部分时间性能都很好),但是如果在高争用情况下锁内有非常少量的工作,那么锁定开销确实会超过实际工作量,并且无锁算法可以显著提高吞吐量

  • ABA绝对适用于x86。这是一个由于CAS本身的基本性质而产生的问题,无论硬件实现如何

  • 我的建议是在编写无锁代码时要非常小心。测试非常困难,而且在某些情况下(例如,在稍有不同的硬件上,或在不同的工作负载下使用时,等等),在bug出现之前(甚至在生产中)可能会工作多年。不要一开始就编写一个像链表一样的通用数据结构,因为在一般情况下,正确处理插入和删除是一个噩梦(至少,如果您的目标是在争用下保持高性能,这通常是因为这就是为什么您首先编写无锁数据结构的原因)。相反,请找出特定应用程序逻辑所需的确切最小操作,并仅实现这些操作。只添加无锁链表编写起来相当简单;由于ABA,包含删除头部或尾部的功能要复杂得多