__sync_val_compare_and_swap vs __sync_bool_compare_and_swap

我一直在考虑这两个函数的返回值。 __sync_bool_compare_and_swap函数的返回值似乎有明显的好处,即我可以用它来判断交换操作是否发生。 但是我看不到__sync_val_compare_and_swap的返回值。

首先,让我们有一个函数签名供参考(来自GCC docs减去var args):

type __sync_val_compare_and_swap (type *ptr, type oldval type newval); 

我看到的问题是__sync_val_compare_and_swap的返回值是* ptr的旧值。 确切地说,一旦适当的记忆障碍得以实施,这是该function的实施所看到的价值。 我明确说明了这一点,以满足在调用__sync_val_compare_and_swap和执行指令以强制执行内存屏障之间的事实,* ptr的值可能很容易改变。

现在,当函数返回该返回值时我能做什么? 尝试将它与* ptr进行比较是没有意义的,因为现在可以在其他线程上更改* ptr。 同样地比较newval和* ptr对我来说也没有什么帮助(除非我锁定* ptr,这可能首先破坏了我对primefaces的使用)。

所以我真正要做的就是询问返回值是否= = oldval,这是否有效(参见下面的警告)询问交换操作是否发生。 所以我本来可以使用__sync_bool_compare_and_swap。

我刚才提到的警告是,我在这里看到的唯一细微差别是,这样做并不能告诉我交换是否发生,它只是告诉我在内存屏障释放之前的某个时刻* ptr有相同的值为newval。 我正在考虑oldval == newval的可能性(虽然我很难看到一种有效实现函数的方法,以便它可以先检查这些值,如果它们是相同的则不交换,所以它可能是一个没有实际意义的点)。 但是我看不出这样一种情况,即知道这种差异会对我在呼叫站点产生影响。 事实上,我无法想象我会将oldval和newval设置为相等的情况。

我的问题是:

是否存在使用__sync_val_compare_and_swap和__sync_bool_compare_and_swap不等效的用例,即是否存在提供比另一个更多信息的情况?

在旁边

我之所以考虑这个问题,是因为我发现__sync_val_compare_and_swap的实现方式与sync_bool_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。 这让我觉得前者必须提供比后者更多的“信息”,但根据我的问题,我并没有看到它确实存在。

__sync_val_compare_and_swap提供的操作总是可以用__sync_val_compare_and_swap来实现(当然其他方向显然是可行的),所以就功率而言,两者是等价的。 但是,根据__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行为,导致失败的值可能会为您提供一个起点,以便更有效地重试操作,或者可能为某些不会“重试”的操作指示失败的有意义原因 。 作为示例,请参阅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 。 在某些方面,这是一个愚蠢的例子,因为它只是通过使用旧值来保存分支或条件移动,但是在其他情况下可能存在多个旧值并且知道导致操作失败的问题。