atomic_dec_if_positive 是如何成为原子的?
How is atomic_dec_if_positive atomic?
所以我正在从 here 的 Linux 源代码中读取 atomic.h
(在 google 上找到它。我不确定它是否合法)并且我可以'围绕着我的想法:
这个原子性如何?
static inline int atomic_dec_if_positive(atomic_t *v)
{
int c, old, dec;
c = atomic_read(v);
for (;;) {
dec = c - 1;
if (unlikely(dec < 0))
break;
old = atomic_cmpxchg((v), c, dec);
if (likely(old == c))
break;
c = old;
}
return dec;
}
它使用函数 atomic_read()
和 atomic_cmpxchg()
,它们肯定会在某处使用微处理器指令集的原子性特性以汇编语言实现。
它首先读取一个值并确保它是正数,将读取的值存储在 c
中,将减后的值存储在 dec
中,然后调用 atomic_cmpxchg()
将自动执行以下操作:"write dec
in *v
only if the value in *v
is equal to c
, and return the old value in *v
"。这样你就可以确保 *v
中的值在两次原子调用之间没有改变。如果失败并且 return 值与 *v
的预期内容不同,它将重试整个过程。
下面一行
c = atomic_read(v);
表示此时我们知道atomic_v变量的值== c。我们
减少 c 给我们我们需要的值。
dec = c - 1;
显然,如果数字不是正数且 0 不是正数,我们不能
减少它。
if (unlikely(dec < 0))
break;
现在我们尝试用预期结果更改已知的旧结果
old = atomic_cmpxchg((v), c, dec);
这定义为
int atomic_cmpxchg(atomic_t *v, int old, int new);
如果我们这样写出来,假设整个函数是原子的。我们有
int atomic_cmpxchg(atomic_t *v, int old, int new) {
&v->counter = &v->counter == old ? new : old;
return old;
}
注意,我将 v
视为一个整数,在 x86 上它是一个结构。此时我们
知道在原子操作发生时我们得到
旧值。我们期望的旧值是 c
,所以如果是这种情况,那么我们有
成功递减值,return结果。
if (likely(old == c))
break;
如果不是,我们需要重置我们的期望值,即我们的起点,我们正在递减一个新值 c
而不是我们上次进入 for(;;)
循环时的旧值
c = old;
这里重要的是这是一个循环,这个循环会一直持续下去,直到成功递减值或者值为非正数。
所以我正在从 here 的 Linux 源代码中读取 atomic.h
(在 google 上找到它。我不确定它是否合法)并且我可以'围绕着我的想法:
这个原子性如何?
static inline int atomic_dec_if_positive(atomic_t *v)
{
int c, old, dec;
c = atomic_read(v);
for (;;) {
dec = c - 1;
if (unlikely(dec < 0))
break;
old = atomic_cmpxchg((v), c, dec);
if (likely(old == c))
break;
c = old;
}
return dec;
}
它使用函数 atomic_read()
和 atomic_cmpxchg()
,它们肯定会在某处使用微处理器指令集的原子性特性以汇编语言实现。
它首先读取一个值并确保它是正数,将读取的值存储在 c
中,将减后的值存储在 dec
中,然后调用 atomic_cmpxchg()
将自动执行以下操作:"write dec
in *v
only if the value in *v
is equal to c
, and return the old value in *v
"。这样你就可以确保 *v
中的值在两次原子调用之间没有改变。如果失败并且 return 值与 *v
的预期内容不同,它将重试整个过程。
下面一行
c = atomic_read(v);
表示此时我们知道atomic_v变量的值== c。我们 减少 c 给我们我们需要的值。
dec = c - 1;
显然,如果数字不是正数且 0 不是正数,我们不能 减少它。
if (unlikely(dec < 0))
break;
现在我们尝试用预期结果更改已知的旧结果
old = atomic_cmpxchg((v), c, dec);
这定义为
int atomic_cmpxchg(atomic_t *v, int old, int new);
如果我们这样写出来,假设整个函数是原子的。我们有
int atomic_cmpxchg(atomic_t *v, int old, int new) {
&v->counter = &v->counter == old ? new : old;
return old;
}
注意,我将 v
视为一个整数,在 x86 上它是一个结构。此时我们
知道在原子操作发生时我们得到
旧值。我们期望的旧值是 c
,所以如果是这种情况,那么我们有
成功递减值,return结果。
if (likely(old == c))
break;
如果不是,我们需要重置我们的期望值,即我们的起点,我们正在递减一个新值 c
而不是我们上次进入 for(;;)
循环时的旧值
c = old;
这里重要的是这是一个循环,这个循环会一直持续下去,直到成功递减值或者值为非正数。