为什么 std::atomic:<T>:compare_exchange_* 不应该受到 ABA 问题的困扰?

Why does std::atomic<T>::compare_exchange_* should not suffer from ABA issue?

本文关键字:ABA 问题 不应该 std lt gt compare exchange 为什么 atomic      更新时间:2023-10-16

在一些论坛和书籍中(即C++操作中的并发)有一个很好的多生产者/多消费者堆栈的例子,在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<T>:compare_exchange_*是否阻止ABA问题
比方说:

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

然后就会出现与ABA相关的问题。

我想我错过了什么。我在这里错过了什么?

干杯

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

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

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

在官方的Concurrent in Action Manning论坛上也有一个关于堆栈实现中ABA问题的帖子。