我一直在考虑这两个函数的返回值。__sync_bool_compare_and_swap函数的返回值似乎有明显的好处,即我可以使用它来判断是否发生了交换操作。但是,我无法很好地使用__sync_val_compare_和_swap的返回值。
首先,让我们有一个函数签名供参考(来自GCC文档减去var args):
type __sync_val_compare_and_swap (type *ptr, type oldval type newval);
我看到的问题是,__sync_val_compare_and_swap的返回值是*ptr的旧值。准确地说,一旦设置了适当的内存屏障,这个函数的实现就会看到它的价值。我明确地声明了这一点,以满足这样一个事实:在调用__sync_val_compare_and_swap和执行指令以加强内存屏障之间,*ptr的值可能很容易更改。
现在,当函数返回时,我能用这个返回值做什么呢?尝试将其与*ptr进行比较是没有意义的,因为*ptr现在可以在其他线程上更改。同样,比较newval和*ptr也没有真正的帮助(除非我锁定*ptr,这可能会破坏我对atomics的使用)。
因此,我真正需要做的就是询问返回值== oldval是否有效(请参阅下面的警告),询问是否进行了交换操作。所以我可以用__sync_bool_compare_and_swap。
我刚才提到的注意事项是,我在这里看到的唯一微妙的区别是,这样做并不能告诉我交换是否发生,它只是告诉我,在内存屏障被释放之前的某个时刻,ptr具有与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;
}
在ret中存储*ptr的竞赛,因为*ptr在调用__sync_bool_compare_and_swap之前可能会更改。这让我意识到,我似乎没有一个安全的方式(没有额外的障碍或锁)实现__sync_val_compare_and_swap的sync_bool_compare_and_swap。这让我认为前者必须提供比后者更多的“信息”,但就我的问题而言,我并不认为它确实提供了“信息”。
发布于 2015-04-28 04:13:51
__sync_val_compare_and_swap
提供的操作总是可以根据__sync_bool_compare_and_swap
实现(当然,另一个方向显然是可能的),因此在功率方面两者是等价的。然而,以__sync_val_compare_and_swap
的形式实现__sync_bool_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中的pthread_spin_trylock
代码(我是该代码的作者):
trylock.c?id=afbcac6826988d12d9a874359cab735049c17500
在那里,a_cas
等同于__sync_val_compare_and_swap
。在某些方面,这是一个愚蠢的例子,因为它只是通过使用旧值来保存分支或条件迁移,但是在其他情况下,多个旧值是可能的,并且知道导致操作失败的值很重要。
https://stackoverflow.com/questions/29909819
复制相似问题