在书籍C++ Concurrency in Action中,作者给出了使用危险指针实现无锁栈数据结构的示例。代码的一部分如下所示:
描述说:
你必须在一个 while 循环中执行此操作,以确保节点在读取旧 head 指针和设置危险指针之间未被删除。在此窗口期间,没有其他线程知道您正在访问此特定节点。幸运的是,如果旧的 head 节点将被删除,则 head 本身必须已更改,因此您可以检查这一点并继续循环,直到您知道 head 指针仍具有与您设置危险指针相同的值。
我认为代码存在缺陷,因为 head 节点受到 ABA 问题的影响。即使 head 的值保持不变,它最初指向的节点可能已被删除。分配了一个新的 head 节点,它恰好具有与先前节点相同的地址值。
std::shared_ptr<T> pop()
{
std::atomic<void*>& hp=get_hazard_pointer_for_current_thread();
node* old_head=head.load();
node* temp;
do
{
temp=old_head;
hp.store(old_head);
old_head=head.load();
} while(old_head!=temp);
// ...
}
描述说:
你必须在一个 while 循环中执行此操作,以确保节点在读取旧 head 指针和设置危险指针之间未被删除。在此窗口期间,没有其他线程知道您正在访问此特定节点。幸运的是,如果旧的 head 节点将被删除,则 head 本身必须已更改,因此您可以检查这一点并继续循环,直到您知道 head 指针仍具有与您设置危险指针相同的值。
我认为代码存在缺陷,因为 head 节点受到 ABA 问题的影响。即使 head 的值保持不变,它最初指向的节点可能已被删除。分配了一个新的 head 节点,它恰好具有与先前节点相同的地址值。
head == old_head
意味着*head
没有变化,而这恰恰是导致 ABA 问题的错误假设,除非我搞错了。 - Caninonos