例如,在intel i3,i5,i7 x86 64位cpu上,CAS仅保证最大值为原子。 8字节对象大小?
在x86 cpu上,锁定指令被添加到CAS操作,例如。 CMPXCHG
,这意味着整个缓存行被锁定用于读取cpu,因此std::atomic::compare_exchange_weak()
不会因为虚假失败原因而返回错误?
如果x86 cpu在CAS操作中使用lock
,如果使用无锁编程而不是在共享资源上使用std :: mutex,性能提升是多少?
如果我想写一个无锁链接列表,例如。我对标头节点的指针执行原子加载,并将其与std::atomic::compare_exchange_weak()
进行比较,以查看是否已进行任何更改。在这种情况下,ABA问题是否适用于x86 cpu?
答案 0 :(得分:4)
你在这里有几个问题: - )
根据定义,CAS操作始终是原子操作。话虽如此,由您的硬件决定支持哪些(如果有的话)CAS操作,包括可以为这种操作交换的最大字节数。某些CPU(例如ARM)根本不直接支持CAS。 x86-64 CPU支持8字节CAS,所有现代CPU也通过CMPXCHG16b
指令支持16字节CAS(通常称为双宽度CAS)。
我不确定CAS是否会在您提到的CPU上发生虚假失败(尽管我知道在某些平台上它没有)。我对这些特定CPU上的缓存架构知之甚少。但是,在compare_exchange_weak
和compare_exchange_strong
之间进行选择时,底层硬件实现是无关紧要的:你应该使用对你正在做的事情有意义的那个 - 如果你只是写一个典型的弱交换小型CAS循环(其中虚假故障的额外工作可以忽略不计),否则进行强有力的交换。这也使您的代码更加便携和健壮。
你需要衡量。它几乎完全取决于您的应用程序正在做什么(如果您的应用程序确实受到围绕共享资源的极高争用的瓶颈,它可能会受益于重新设计,首先需要较少的共享)。一般来说,std::mutex
“足够好”(实际上大部分时间都是非常好的),但是如果你在高争用的锁中有很少量的工作,那么锁定开销确实会超过实际工作量,无锁算法可以显着提高吞吐量。
ABA绝对适用于x86。无论硬件实现如何,这都是由于CAS本身的基本特性而产生的问题。我wrote a little about it here。
我的建议是在编写无锁代码时要非常小心。在某些极端情况下(例如,在略有不同的硬件上,或在不同的工作负载下使用等),错误变得可见之前,测试非常困难,并且可能工作(甚至在生产中)多年。不要开始编写像链接列表这样的通用数据结构,因为在一般情况下正确处理插入和删除是一场噩梦(至少,如果你的目标是在竞争中保持高性能,那就是它通常是因为这就是你最初编写无锁数据结构的原因)。相反,找出您的特定应用程序逻辑所需的确切最小操作,并仅实现这些操作。一个只添加无锁的链表是非常容易编写的;由于ABA,结合去除头部或尾部的能力要复杂得多。