c++ - 为什么 std::atomic<T>::compare_exchange_* 不应遭受 ABA 问题?

标签 c++ multithreading atomic lock-free compare-and-swap

在一些论坛和书籍(即C++ Concurrency in Action)中,有一个很好的多生产者/多消费者堆栈示例,并且在pop实现中他们通常这样做以下:


// head is an std::atomic<node*> variable
node *old_head = head.load();
while(old_head && !head.compare_exchange_weak(old_head, old_head->next));
...
为什么使用 std::atomic::compare_exchange_* 可以防止 ABA 问题?
这么说吧:

  • old_head->next 在线程被抢占之前(就在compare_exchange_weak之前)获得resolved
  • 然后 BA 场景就会发生
  • 线程恢复后head == old_head有效;在这种情况下,old_head->next 不会再次解析,指向无效的内存位置
  • compare_exchange_weak 将被执行并通过,但值 old_head->next 仍将是

然后就会发生 ABA 相关问题。

我相信我错过了一些东西。我在这里缺少什么?

干杯

最佳答案

是的,你会在这里遇到 ABA 问题。

不过,我认为这并不重要,因为您所指的实现(CiA 中的列表 7.3)无论如何都是无效的,它正在泄漏节点。

如果我们看一下最简单的引用计数实现,即使用无锁 std::shared_ptr(CiA 中的列表 7.9)的实现,我们会发现问题不会发生。当使用共享指针时,old_head不会被删除,因为我们的线程仍然保留着对它的引用,因此新创建的头无法在旧头的内存地址中创建。

官方也有一个帖子Concurrency in Action Manning forums关于堆栈实现中的ABA问题。

关于c++ - 为什么 std::atomic<T>::compare_exchange_* 不应遭受 ABA 问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20173766/

相关文章:

c++ - 如何使用 dear imgui 填充两条贝塞尔曲线之间的区域

c++ - "const"函数有什么用?

java - 重入锁 : Lock/Unlock speed in single-threaded application

c - 杀死子进程后终端中的不可见文本

c++ - 如何在 C++ 中混合原子和非原子操作?

java - AtomicBoolean 的这种使用是同步块(synchronized block)的有效替代吗?

c++ - WASAPI 独占/事件模式导致嗡嗡声

python - 验证随时间变化的连续条件

c++ - 如何使用 C++11 原子库实现 seqlock 锁

c++ - Visual Studio 2017 : Speed up C++ IntelliSense