1

我正在寻找一种简单、有效的方法来使用 GCC 原子内置函数来实现简单的 fetchAndSet。我在这里看到的最接近的是__sync_lock_test_and_set内置函数,但它不会像其他函数那样发出完整的内存屏障,并且所有其他函数要么执行操作(add、sub、xor 等),要么是有条件的(比较和交换功能)。这些不起作用,因为我试图操纵一个保存任意指针数据的变量。

我能想到的最好的是这样的:

type *fetchAndSet(type **loc, type *newvar) {
  while (1) {
    type *oldvar = __sync_fetch_and_add(loc, 0);
    if (__sync_bool_compare_and_swap(loc, oldvar, newvar)) return oldvar;
  }
}

...换句话说,我在内存位置以原子方式获取值,然后在我成功用新值替换旧值后立即退出循环。我对这个解决方案并不满意,因为它不是一个单一的原子操作,如果两个或多个线程争夺同一个内存位置,就会有相当大的饥饿风险。所以,我的问题:有没有更好的方法来做到这一点?

4

2 回答 2

2

最新版本的 GCC 具有为实现 C11 设计的新原子内置函数stdatomic.h。请参阅http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/_005f_005fatomic-Builtins.html。不幸的是,我不确定添加这些的第一个版本是什么,因此根据您的兼容性需求,它们可能不适合(但您可以像已经在做的那样使用丑陋的后备)。您还可以为您关心的特定 CPU 包含内联汇编;在 x86 上这很简单:

__asm__ __volatile__ ( "xchg %0,%1" : "+r"(val), "+m"(*ptr) : : "memory" );

从长远来看,您应该使用stdatomic.h,但不幸的是我们还没有...

于 2013-05-12T00:00:58.177 回答
1

使用 gcc 4.6 中的内置函数(根据您的链接),您可以将示例代码更改为(理想情况下)只发出一条同步指令,因为您不需要使用同步来获取值。

type *fetchAndSet(type **loc, type *newvar) {
  while (1) {
    type *oldvar = *loc;
    if (__sync_val_compare_and_swap(loc, oldvar, newvar) == oldvar) return oldvar;
  }
}

第二种选择是在调用 __sync_lock_test_and_set() 之前添加 __sync_synchronize(),以便存在完整的屏障。

超越 gcc 4.6 中的内置函数,我建议您参考 R 的答案。

于 2013-05-12T00:58:18.680 回答