Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何比较交换C和x2B+;函数决定比赛条件?_C++_Multithreading_X86 64_Atomic_Compare And Swap - Fatal编程技术网

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