gcc原子内置函数

时间:2011-07-22 06:13:03

标签: c gcc atomic

http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html

我相信以下代码会原子地增加var的值。

volatile int var = 0;
__sync_fetch_and_add( &var, 1 )

我将上述代码理解为以下逻辑

  1. 加载变量var的地址
  2. 将数字1写入变量var atomically - 通过寄存器/缓存,不知何故
  3. 但是,我怀疑以下是否也是原子的

    volatile int var = 0;
    volatile int num = 1;
    __sync_fetch_and_add( &var, num )
    

    因为它可能被解释为

    1. 加载变量var的地址
    2. 将变量num的值加载到寄存器
    3. 将值写入变量var。
    4. 执行#2之后,但在#3之前, CPU /线程被中断,另一个CPU /线程更新 变量num。

      的值

      换句话说, 当使用gcc的_ sync *()时, 我可以使用变量而不是常量作为第二个参数吗?

      它不会破坏原子性吗?

1 个答案:

答案 0 :(得分:29)

该操作实际上是两个操作。

__sync_fetch_and_add( &var, num )

加载num是原子的。将其添加到var是原子的。但是两个原子操作放在一起时不会进行原子操作。这就是为什么发明新的无锁数据结构如此困难的原因。 通常,两个线程安全的操作在编写时不一定会进行线程安全的操作。这就是为什么制作正确的多线程应用程序非常困难的原因。

你看,__sync_fetch_and_add 确实是原子,但它的行为类似于普通函数 - 因此它将当前值“num”作为参数。说函数的原子性被破坏是不正确的 - 因为调用者负责从num加载值,并且它不是函数接口的一部分。我同样可以抱怨这个:

__sync_fetch_and_add(&var, some_really_long_function());

或者更糟,

__sync_fetch_and_add(long_function_1(), long_function_2());

你说它“可能被解释为”

  1. 加载变量var的地址
  2. 加载变量num的值
  3. 执行原子添加
  4. 但根据C规范,并不是可能以这种方式解释,而是必须以这种方式解释,否则编译器不会符合(实际上,它可以交换#1和#2,但这在这里并不重要)。