【发布时间】:2020-03-20 02:16:45
【问题描述】:
我遇到了这个旧的(4.8.3 之前的 GCC -- 错误 60272)错误报告 https://gcc.gnu.org/ml/gcc-bugs/2014-02/msg01951.html。现在已修复。但我对此有一个疑问。我编译了以下代码sn -p
#include <atomic>
struct Node { Node* next; };
void Push(std::atomic<Node*>& head, Node* node)
{
node->next = head.load();
while(!head.compare_exchange_weak(node->next, node))
;
}
void Pop(std::atomic<Node*>& head){
for(;;){
Node* value=head.exchange(nullptr);
if(value){
delete value;
break;
}
}
}
与:
g++ -S -std=c++11 -pthread -O3 test.cc -o test.S
生成的程序集有以下内容(我只放了相关部分):
.....
4 .L4:
5 lock cmpxchgq %rsi, (%rdi)
6 jne .L6
7 rep ret
8 .p2align 4,,10
9 .p2align 3
10 .L6:
11 movq %rax, (%rsi)
12 jmp .L4
.....
这是我的问题。假设这段代码与 2 个线程同时运行。对于 T1,第 5 行被执行,然后 T1 被中断,T2 做了一些可能使队列弹出完成的事情。当操作系统重新安排 T1 时,它将从第 6 行恢复,在执行 jne 之前有人应该**重新评估**条件。但是如果不重新评估它,那么这可能会导致内存损坏。我的想法是否正确?
【问题讨论】:
-
比较和交换操作旨在始终保持队列不受污染。如果成功,则队列正确更新,如果没有,则可以在下一次迭代中构建新的正确队列。在第 6 行,队列已经正确更新,测试是在 CAS 失败时继续循环。
-
如果您想知道
lock cmpxchg如何实现原子性,请参阅 Can num++ be atomic for 'int num'? 了解有关lock前缀如何工作的更多信息。
标签: c++ gcc assembly x86-64 lockless