ldrex / strex如何使ARM中的atomic_add成为原子操作?

1 arm atomic inline-assembly linux-kernel load-link-store-conditional

根据http://lxr.free-electrons.com/source/arch/arm/include/asm/atomic.h#L31

 static inline void atomic_add(int i, atomic_t *v)
 41 {
 42         unsigned long tmp;
 43         int result;
 44 
 45         prefetchw(&v->counter);
 46         __asm__ __volatile__("@ atomic_add\n"
 47 "1:     ldrex   %0, [%3]\n"
 48 "       add     %0, %0, %4\n"
 49 "       strex   %1, %0, [%3]\n"
 50 "       teq     %1, #0\n"
 51 "       bne     1b"
 52         : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
 53         : "r" (&v->counter), "Ir" (i)
 54         : "cc");
 55 }
Run Code Online (Sandbox Code Playgroud)

可以抢占,怎么能叫“原子”呢?

gna*_*729 5

您似乎完全误解了原子操作是什么。

显然,如果您查看值 x,发现该值为 13,然后调用atomic_add 函数将其增加 5,则新结果可以是任何值,因为另一个线程可能在调用atomic_add 之前更改了该值。同样,如果您检查结果,它也可能是任何内容,因为另一个线程可能会更改atomic_add 和您的检查之间的结果。

atomic_add 函数保证让值增加该数量。这就是它的作用。如何实现这一点并不重要。如果一百个线程调用atomic_add(5, &x),那么x最终会增加500。这才是重要的。

这是在 ARM 和 PowerPC 等处理器上执行原子操作的典型方法,这些处理器具有保留内存位置的指令和检查保留是否仍然存在的存储指令。

  • 原子并不意味着“在一个周期内”。大多数情况下,由于所需的簿记开销,原子指令所花费的时间将远远超过单个周期。这意味着你的价值观会随着你想要发生的事情实际发生而改变。如果另一个线程会更改加载和存储之间的值,您的结果通常会以某种方式损坏。原子操作保证操作作为块完成。对于关键部分,您只需将原子部分转移到锁定指令中即可。所以最终你会得到开销而没有任何收益。 (4认同)