【问题标题】:Real-world examples for ABA in multithreading [closed]多线程中 ABA 的真实示例 [关闭]
【发布时间】:2013-01-10 06:02:23
【问题描述】:

我正在寻找一些在多线程代码中引起问题的 ABA 问题的真实示例。

在执行原子compare-and-swap指令时,并发代码中会出现ABA问题。如果线程在执行比较和交换之前立即中断,则第二个线程可能会将比较和交换的目标从其初始值 A 更改为不同的值 B。如果然后将值更改回 A在第一个线程恢复之前,尽管目标值发生了变化,比较和交换仍将成功。

在许多情况下,ABA 不是问题。以共享引用计数为例:即使 refcount 并发改变我们也没有问题,只要我们从不从已经下降到 0 的 refcount 增加。所以我们显然只关心目标是否匹配交换时的预期值,而不是过去是否发生变化。

wikipedia page 有一个受 ABA 影响的无锁堆栈实现示例,但我个人到目前为止还没有在生产代码中遇到过这个问题。我只是想知道是否有人有一些关于 ABA 的精彩战争故事要分享。

【问题讨论】:

    标签: multithreading concurrency atomic compare-and-swap


    【解决方案1】:

    假设您想使用传统的链表实现有序列表。假设您想在列表中添加一个新值 V。首先,你要找到合适的位置,使用辅助指针AUX插入新元素,并将其定位在最后一个值小于V的节点,同时保存AUX->next,以便在CAS操作中进行比较。一旦有了引用,您将 NEW->next 指向 AUX->next,然后使用 CAS 如果 AUX->next 仍然是您保存的相同引用,则将 AUX->next 切换到 NEW。应该是这样的:

    AUX = list.HEAD;
    WHILE( AUX->next.value < V)
        AUX = AUX->next;
    OLD = AUX->next; //line 4
    NEW->next = AUX->next; //line 5
    IF( CAS(AUX->next, NEW, OLD)) //line 6
        Success!!!
    ELSE
        Try again or whatever
    

    这是最简单的方法。问题是在第 4 行和第 5 行之间,另一个线程可能已经删除了“OLD”,然后插入了另一个小于 V 但仍大于 AUX.value 的元素 X。如果发生这种情况,并且分配给值为 X 的节点的内存与曾经拥有 OLD 的地址相同,则 CAS 会成功,但列表不会被排序。如果第二个线程的动作发生在第 5 行和第 6 行之间,您将丢失值为 X 的节点。所有这些都是因为 ABA 问题。

    【讨论】:

    • 不应该是CAS(AUX-&gt;next, NEW, OLD)CAS(AUX-&gt;next, OLD, NEW)
    猜你喜欢
    • 2010-09-11
    • 2012-12-04
    • 2019-12-16
    • 2010-11-03
    • 2012-01-07
    • 2011-02-01
    • 2012-03-27
    • 1970-01-01
    • 2016-01-31
    相关资源
    最近更新 更多