__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 的代码(我是作者):

http://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_spin_trylock.c?id=afbcac6826988d12d9a874359cab735049c17500

a_cas等价于__sync_val_compare_and_swap。在某些方面,这是一个愚蠢的例子,因为它只是通过使用旧值来保存分支或条件移动,但在其他情况下,多个旧值是可能的并且知道导致操作失败的那个很重要。