C++ 如何比较交换C和x2B+;函数决定比赛条件?
如我们所知,C++ 如何比较交换C和x2B+;函数决定比赛条件?,c++,multithreading,x86-64,atomic,compare-and-swap,C++,Multithreading,X86 64,Atomic,Compare And Swap,如我们所知,compare\u exchange\u weak()如果存在争用条件,则返回一个错误(假值),因此操作无法完全完成。但竞争条件究竟是如何由compare\u exchange\u weak()确定的呢 如果有多个线程尝试读取/写入值,则指令是否会返回错误,也就是说,获取一个锁,并且正是通过这种方式比较交换\u弱确定竞争条件?cmpxchg指令影响ZF标志:如果交换成功,则设置该标志,否则清除该标志 让我们通过一个例子来了解这一点: std::atomic<int> a;
compare\u exchange\u weak()
如果存在争用条件,则返回一个错误(假值),因此操作无法完全完成。但竞争条件究竟是如何由compare\u exchange\u weak()
确定的呢
如果有多个线程尝试读取/写入值,则指令是否会返回错误,也就是说,获取一个锁,并且正是通过这种方式
比较交换\u弱
确定竞争条件?cmpxchg指令影响ZF
标志:如果交换成功,则设置该标志,否则清除该标志
让我们通过一个例子来了解这一点:
std::atomic<int> a;
bool my_compare_exchange(int expected, int desired) {
bool succeeded = a.compare_exchange_weak(expected, desired);
return succeeded;
}
如果交换成功(即,
ZF
由cmpxchg
设置),则使用sete al
将寄存器al
设置为1
)。否则,它被设置为零(即,ZF
被cmpxchg
清除)。锁定cmpxchg
是原子的;在执行过程中不会发生任何事情(逻辑上无论如何)。与compare\u exchange\u weak
的LL/SC实现不同,当另一个线程在同一缓存线中写入时,它不会错误地失败,只有当比较实际失败时。()
compare\u exchange\u strong
可以实现为lock cmpxchg
而无需循环
您是否在询问加载旧值、修改旧值,然后尝试将新值固定到位的用例?(例如,合成硬件不直接提供的原子操作,例如,或) 在这种情况下,是的,
cmpxchg
失败的原因是与另一个线程的竞争
作为@ネロク 说明:您可以检查cmpxchg
的标志结果,以获得compare\u exchange\u strong
的布尔结果,即判断比较部分是否失败以及存储是否完成。看
lock cmpxchg
还有其他用例,比如通过旋转lock来等待自旋锁变为可用。比较\u exchange\u弱(0,1)
,反复尝试将未锁定的变量转换为锁定状态。因此,失败的CAS不是来自竞争条件,它只是来自仍然保持的锁。(因为您传递的是一个常量作为“预期值”,而不是从该位置读取的值。)
这通常不是个好主意。我认为,通常最好是在等待锁时旋转只读,并且只有在看到可用的情况下,才尝试使用CAS或XCHG获取锁。(使用xchg
并测试整数结果可能比lock cmpxchg
更便宜,可能会使缓存线锁定更少的周期。)
TL:DR:如果你想对正确性进行推理,无锁编程需要精确的语言
cmpxchg
执行时,如果EAX与内存中的值不匹配,则会失败并清除ZF(创建ne
不相等条件)。指令本身并不知道或关心种族,只知道它自己执行时的确切状态
作为一名程序员,当使用它作为构建块来创建更大的原子操作时,你必须担心竞争和重试。你知道这个Q/a吗?@Scheff谢谢,我已经阅读了这个Q/a并找到了很多有用的信息,但我仍然没有找到答案。我只是想知道,compare_exchange_uuu函数到底是如何检测到竞争条件的。我在谷歌上搜索了“compare_exchange_弱()锁cmpxchg”。我的印象是,关于Intel x86/x64,所有这些在C++11中考虑的关于锁定的微妙细节都没有那么重要,因为Intel命令没有那么多样化。我找不到可以链接为“证据”的东西,但您可以搜索自己以“获得感觉”。我非常确定,在x86上,compare\u exchange\u weak与compare\u exchange\u strong的功能相同
cmpxchg
指令设置ZF(零标志),这取决于值是否相等并因此发生了更改。谢谢,现在我了解了compare_exchange如何检测竞争条件。但我还有两个新问题:)首先,lock
prefix是否会自动执行下一条指令,因此cmpxchg
将正确执行,但还有sete al
指令,为什么它不会自动执行?如果线程尝试将值设置为al
registerNo,al
不会干扰,因为每个线程都有自己的al
寄存器(al
在线程之间不共享)。堆栈也是如此。唯一的原子指令是lock cmpxchg
。哎呀,我现在打开它,看到的汇编代码与您的完全相同,谢谢!我接受你的回答
my_compare_exchange:
mov eax, edi
lock cmpxchg DWORD PTR a[rip], esi
sete al // <-- conditional instruction
ret