__sync_val_compare_and_swap 对比 __sync_bool_compare_and_swap
__sync_val_compare_and_swap vs __sync_bool_compare_and_swap
我一直在思考这两个函数的return值。 __sync_bool_compare_and_swap 函数的 return 值似乎有明显的好处,即我可以用它来判断交换操作是否发生。但是我看不到 __sync_val_compare_and_swap 的 return 值的良好用途。
首先,让我们有一个函数签名供参考(来自 GCC 文档减去 var args):
type __sync_val_compare_and_swap (type *ptr, type oldval type newval);
我看到的问题是 __sync_val_compare_and_swap 的 return 值是 *ptr 的旧值。准确地说,这是在设置了适当的内存屏障后,此函数的实现所看到的值。我明确声明这一点是为了满足这样一个事实,即在调用 __sync_val_compare_and_swap 和执行指令以强制执行内存屏障之间,*ptr 的值很容易改变。
现在,当函数 return 出现时,我可以用那个 return 值做什么?尝试将它与 *ptr 进行比较是没有意义的,因为现在可以在其他线程上更改 *ptr。同样,比较 newval 和 *ptr 对我也没有真正的帮助(除非我锁定 *ptr 这可能首先破坏了我对原子的使用)。
所以我真正要做的就是询问 return 值是否 == oldval,这实际上是(请参阅下面的警告)询问交换操作是否发生。所以我可以直接使用 __sync_bool_compare_and_swap。
我刚才提到的警告是,我在这里看到的唯一细微差别是,这样做并不能告诉我交换是否发生,它只是告诉我在释放内存屏障之前的某个时刻*ptr 与 newval 具有相同的值。我正在考虑 oldval == newval 的可能性(尽管我很难找到一种有效实现该功能的方法,以便它可以首先检查这些值,如果它们相同则不交换,所以这可能是一个有争议的问题)。但是,我看不到知道这种差异会在呼叫站点对我产生影响的情况。事实上,我无法想象我会将 oldval 和 newval 设置为相等的情况。
我的问题是:
是否存在任何使用 __sync_val_compare_and_swap 和 __sync_bool_compare_and_swap 不等同的用例,即是否存在其中一个提供的信息比另一个提供更多信息的情况?
一边
我考虑这个的原因是我根据 sync_bool_compare_and_swap 找到了 __sync_val_compare_and_swap 的实现,它有一个种族:
inline int32_t __sync_val_compare_and_swap(volatile int32_t* ptr, int32_t oldval, int32_t newval)
{
int32_t ret = *ptr;
(void)__sync_bool_compare_and_swap(ptr, oldval, newval);
return ret;
}
竞争正在将 *ptr 存储在 ret 中,因为 *ptr 可能会在调用 __sync_bool_compare_and_swap 之前发生变化。这让我意识到我似乎没有一种安全的方法(没有额外的障碍或锁)来根据 sync_bool_compare_and_swap 实现 __sync_val_compare_and_swap。这让我想到前者必须比后者提供更多 "information",但根据我的问题,我看不出它确实如此。
__sync_val_compare_and_swap
提供的操作总可以用__sync_bool_compare_and_swap
来实现(当然另一个方向显然也是可以的),所以在power 两者是等价的。然而,根据 __sync_bool_compare_and_swap
实施 __sync_val_compare_and_swap
并不是很有效。它看起来像:
for (;;) {
bool success = __sync_bool_compare_and_swap(ptr, oldval, newval);
if (success) return oldval;
type tmp = *ptr;
__sync_synchronize();
if (tmp != oldval) return tmp;
}
需要额外的工作,因为您可以观察到 __sync_bool_compare_and_swap
的失败,然后从 *ptr
中读取一个恰好匹配 oldval
.
的新值
至于 为什么 您可能更喜欢 __sync_val_compare_and_swap
行为,导致失败的值可能会为您提供一个更有效地重试操作的起点,或者可能表明有意义的 原因 某些不会 "retried" 的操作失败。例如,请参阅 musl libc 中 pthread_spin_trylock
的代码(我是作者):
有a_cas
等价于__sync_val_compare_and_swap
。在某些方面,这是一个愚蠢的例子,因为它只是通过使用旧值来保存分支或条件移动,但在其他情况下,多个旧值是可能的并且知道导致操作失败的那个很重要。
我一直在思考这两个函数的return值。 __sync_bool_compare_and_swap 函数的 return 值似乎有明显的好处,即我可以用它来判断交换操作是否发生。但是我看不到 __sync_val_compare_and_swap 的 return 值的良好用途。
首先,让我们有一个函数签名供参考(来自 GCC 文档减去 var args):
type __sync_val_compare_and_swap (type *ptr, type oldval type newval);
我看到的问题是 __sync_val_compare_and_swap 的 return 值是 *ptr 的旧值。准确地说,这是在设置了适当的内存屏障后,此函数的实现所看到的值。我明确声明这一点是为了满足这样一个事实,即在调用 __sync_val_compare_and_swap 和执行指令以强制执行内存屏障之间,*ptr 的值很容易改变。
现在,当函数 return 出现时,我可以用那个 return 值做什么?尝试将它与 *ptr 进行比较是没有意义的,因为现在可以在其他线程上更改 *ptr。同样,比较 newval 和 *ptr 对我也没有真正的帮助(除非我锁定 *ptr 这可能首先破坏了我对原子的使用)。
所以我真正要做的就是询问 return 值是否 == oldval,这实际上是(请参阅下面的警告)询问交换操作是否发生。所以我可以直接使用 __sync_bool_compare_and_swap。
我刚才提到的警告是,我在这里看到的唯一细微差别是,这样做并不能告诉我交换是否发生,它只是告诉我在释放内存屏障之前的某个时刻*ptr 与 newval 具有相同的值。我正在考虑 oldval == newval 的可能性(尽管我很难找到一种有效实现该功能的方法,以便它可以首先检查这些值,如果它们相同则不交换,所以这可能是一个有争议的问题)。但是,我看不到知道这种差异会在呼叫站点对我产生影响的情况。事实上,我无法想象我会将 oldval 和 newval 设置为相等的情况。
我的问题是:
是否存在任何使用 __sync_val_compare_and_swap 和 __sync_bool_compare_and_swap 不等同的用例,即是否存在其中一个提供的信息比另一个提供更多信息的情况?
一边
我考虑这个的原因是我根据 sync_bool_compare_and_swap 找到了 __sync_val_compare_and_swap 的实现,它有一个种族:
inline int32_t __sync_val_compare_and_swap(volatile int32_t* ptr, int32_t oldval, int32_t newval)
{
int32_t ret = *ptr;
(void)__sync_bool_compare_and_swap(ptr, oldval, newval);
return ret;
}
竞争正在将 *ptr 存储在 ret 中,因为 *ptr 可能会在调用 __sync_bool_compare_and_swap 之前发生变化。这让我意识到我似乎没有一种安全的方法(没有额外的障碍或锁)来根据 sync_bool_compare_and_swap 实现 __sync_val_compare_and_swap。这让我想到前者必须比后者提供更多 "information",但根据我的问题,我看不出它确实如此。
__sync_val_compare_and_swap
提供的操作总可以用__sync_bool_compare_and_swap
来实现(当然另一个方向显然也是可以的),所以在power 两者是等价的。然而,根据 __sync_bool_compare_and_swap
实施 __sync_val_compare_and_swap
并不是很有效。它看起来像:
for (;;) {
bool success = __sync_bool_compare_and_swap(ptr, oldval, newval);
if (success) return oldval;
type tmp = *ptr;
__sync_synchronize();
if (tmp != oldval) return tmp;
}
需要额外的工作,因为您可以观察到 __sync_bool_compare_and_swap
的失败,然后从 *ptr
中读取一个恰好匹配 oldval
.
至于 为什么 您可能更喜欢 __sync_val_compare_and_swap
行为,导致失败的值可能会为您提供一个更有效地重试操作的起点,或者可能表明有意义的 原因 某些不会 "retried" 的操作失败。例如,请参阅 musl libc 中 pthread_spin_trylock
的代码(我是作者):
有a_cas
等价于__sync_val_compare_and_swap
。在某些方面,这是一个愚蠢的例子,因为它只是通过使用旧值来保存分支或条件移动,但在其他情况下,多个旧值是可能的并且知道导致操作失败的那个很重要。