为什么像 fetch-and-add return 这样的原子操作会改变变量的旧值?

Why do atomic operations like fetch-and-add return the old value of the variable being changed?

我正在努力学习并更好地理解多线程,但我对获取和添加等原子函数的行为很着迷。在 fetch-and-add 的特定情况下,我的理解是一个值(假设 x 当前等于 5)被增加一个增量值(假设 3),结果和(8)被写入 x 的放在内存中,但旧值 (5) 已 returned。

在不同的地方(如 OpenGL 的原子函数、Java 的 AtomicIntegers,以及更多领域)还有其他几个这样的函数,其行为与此类似。但我不明白的是为什么代码中的某个地方想要写入内存,但仍然 return 它首先想要修改的值。任何人都可以帮助阐明这一点吗?

答案很简单。原子函数的本质是它们在执行时修改(在这种情况下增加)实际值,这可能与您的代码知道的值不同。

示例:

x = 5; // x is global
y = atomically_increment(x);
// what is y? 

现在,如果 x 恰好在增量实际发生之前从 5 变为 6,则 y 等于 6,而 x 等于 9。

获取并添加指令或操作(如 x86 的 XADD)使您免于执行 CAS 循环并提供预期初始值的麻烦。

然而,这也意味着在您的代码中,在获取和添加成功之后,您不知道您的增量添加了什么值,并且在激烈的竞争中,读取获取和添加之前的值它可能离真相还很远。这就是为什么作为原子获取和添加的结果返回旧值或新值非常有用的原因。

例如,Aeron uses the value returned by fetch-and-add in order to determine whether it should rotate its buffer (see https://youtu.be/eKVpea51tvo?t=31m54s).

扩展谢尔盖的回答...

我认为 fetch-and-add 类似于信号量;除了 fetch-and-add 调用使​​一切成为原子操作。下面是一个算法示例,它显示了原始值的使用:http://research.omicsgroup.org/index.php/Ticket_lock