2

在一些论坛和书籍(即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<T>::compare_exchange_*会阻止 ABA 问题?
让我们这么说:

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

然后会发生与ABA相关的问题。

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

干杯

4

1 回答 1

2

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

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

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

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

于 2013-11-24T13:44:18.480 回答