c++ - 在x86 cpu上进行比较和交流

标签 c++ multithreading cas lock-free

例如,在 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 ,性能增益是多少?

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

最佳答案

你在这里有几个问题:-)

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

  2. 我不确定 CAS 是否会在您提到的 CPU 上出现虚假故障(尽管我知道在某些平台上它不会)。我对那些特定 CPU 上的缓存架构了解不够。但是,在 compare_exchange_weakcompare_exchange_strong 之间进行选择时,底层硬件实现是无关紧要的:您应该使用对您正在做的事情有意义的一个 - 如果您'只是编写一个典型的小型 CAS 循环(其中对虚假故障的额外工作可以忽略不计),否则就是一个强大的交换。这也使您的代码更具可移植性和健壮性。

  3. 您需要测量。这几乎完全取决于您的应用程序在做什么(如果您的应用程序确实因围绕共享资源的极度争用而成为瓶颈,它可能会受益于首先需要较少共享的重新设计)。一般来说 std::mutex 是“足够好”(实际上大多数时候性能都很好),但是如果在高争用情况下锁内的工作量非常小,那么锁定开销确实会大大降低实际工作量和无锁算法可以显着提高吞吐量。

  4. ABA 绝对适用于 x86。这是由于 CAS 本身的基本性质而出现的问题,与硬件实现无关。我 wrote a little about it here .

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

关于c++ - 在x86 cpu上进行比较和交流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34842152/

相关文章:

c++ - 我的类型在 std 函数中未能通过 enable_if 谓词。有没有办法 "debug"谓词?

c++ - 标准容器作为多线程应用程序中的局部变量

c# - 异步多播委托(delegate)

grails - 无法使用CAS和Spring Security登录到应用程序

c++ - MFC120u.dll "missing"

c++ - 当返回 undefined object 类型引用的 C++ 函数的返回值未赋值时会发生什么?

c++ - 在声明与实现中访问方法

java - 是否有必要使原始实例变量可变?

java - 如何在Java中拥有 volatile boolean 值数组而不是 volatile boolean 值数组?

ruby-on-rails - Devise 和 devise_cas_authenticable 出现 PG::UniqueViolation 错误