c++ - 这段代码如何不能解决 ABA 问题?
问题描述
我试图了解无锁堆栈中的 ABA 问题。根据维基百科:
我们有一个堆栈 A,B,C。
- thread_1 尝试弹出 A。将 old_value 读取为 A,将下一个值读取为 B。在 thread_1 启动 cas 循环之前:
- thread_2进来弹出A,然后
- thread_3进来弹出B,然后
- thread_4 进来并推动 A。
- 堆栈现在是 A,C。thread_1 恢复并看到 A 并将头部设置为 B 而不是 C。你去吧,数据损坏。B 不存在,被线程 B 删除。
我有以下实现:
class Stack
{
struct Node { Node* next; };
std::atomic<Node*> head;
public:
void push()
{
auto node = new Node{ head.load() };
while(!head.compare_exchange_weak(node->next, node));
}
void pop()
{
auto old_head = head.load();
while(!head.compare_exchange_weak(old_head, old_head->next));
}
};
我知道这个实现并没有解决 ABA 问题,但我不知道为什么。我查看了汇编代码:
推
mov rax, QWORD PTR [rdx]
$LL2@push:
lock cmpxchg QWORD PTR [rbx], rdx
je SHORT $LN18@push [to exit the function]
mov QWORD PTR [rdx], rax <----- **AFTER** the CAS the head->next pointer is loaded
jmp SHORT $LL2@push
流行音乐
mov rax, QWORD PTR [rcx]
$LL2@pop:
mov rdx, QWORD PTR [rax] <----- **BEFORE** the CAS the head->next pointer is loaded
lock cmpxchg QWORD PTR [rcx], rdx
jne SHORT $LL2@pop
汇编代码似乎在执行 CAS 之前加载了 old_head->next 指针。因此,当 thread_1 恢复时,它只会加载指向 C 的正确 next 指针,而这段代码似乎可以解决 ABA 问题。问题一定出在其他地方,我找不到。
解决方案
推荐阅读
- c# - Application.ThreadException 在 try... catch 块之前触发
- selenium - Link 有 Javascript 时无法通过 XPath 找到元素
- alluxio - 关于Alluxio中level0.dirs.quota和alluxio.user.file.write.tier.default的配置问题
- powershell - 执行 power shell 脚本时出错
- gradle - 更改flutter使用的默认gradle文件夹路径
- c++ - 链接 OpenCV 失败,LNK 2019 未解析的外部符号
- javascript - 如何使用 Next.js 实现 Quill 或 Draft.js 等富文本编辑器?
- powershell - 使用 Powershell 脚本创建任务计划程序
- python - 如何删除“。” 和字符串中的“-”?
- python - 使用TCP同时在两个进程之间进行多处理连接