CMPXCHG——忽略 ZF 标志安全吗?

CMPXCHG – safe to ignore the ZF flag?

cmpxchg的操作伪代码如下(Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M, 2010):

IF accumulator = DEST
THEN
ZF ← 1;
DEST ← SRC;
ELSE
ZF ← 0;
accumulator ← DEST;
FI;

至少在第一眼看来,累加器会更改其值 如果(且仅当) ZF = 0。 那么,是安全还是完全忽略ZF,只看累加器值的变化来判断操作是否成功?

换句话说,我可以安全地使用变体 #2 而不是 #1 吗?

#1:

mov eax, r8d
lock cmpxchg [rdx], ecx
jz @success

#2:

mov eax, r8d
lock cmpxchg [rdx], ecx
cmp eax, r8d
jz @success

我的意思是,有没有一些非常特殊的情况,只看ZF就可以真正显示操作是否成功?这可能是一个微不足道的问题,但无锁多任务几乎不可能调试,所以我必须 101% 确定。

我认为你的推理是正确的。
将指令浪费到 re-generate ZF 不会导致正确性问题,如果 cmp 可以与 JCC 融合,则只会花费 code-size。不过,与仅使用 EAX 中的旧值进行替换相比,还需要额外的寄存器。

这可能就是为什么 GNU C 的 old-style __sync builtins(已被采用 memory-order 参数的 __atomic 内置函数废弃)仅提供 __sync_val_compare_and_swap__sync_bool_compare_and_swap return 值 布尔成功结果,没有一个内置函数 return 两者都是。

(较新的 __atomic_compare_exchange_n 更像是 C11/C++11 API,通过引用更新 expected,并且 return ing a bool。这可以让 GCC 不会浪费带有 cmp 的指令。)