ARM原子的atomic_add?

时间:2014-05-19 09:31:36

标签: linux-kernel arm

根据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 }

当它可以被抢占时如何被称为原子

2 个答案:

答案 0 :(得分:4)

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

很明显,如果你看一个值x,看看值是13,然后调用一个使它增加5的atomic_add函数,新结果可能是任何东西,因为另一个线程可能在atomic_add之前更改了值被称为。同样,如果你检查结果,它可能再次是任何东西,因为另一个线程可以改变atomic_add和你的检查之间的结果。

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

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

答案 1 :(得分:-1)

ldrexstrex采用不同的默认来实现原子指令。传统的compare and swap(简称CAS)在无锁编程方面存在局限性。 load link/store conditional(简称LL / SC)是原子指令的更高级形式,它允许原子链接列表;比较它们并考虑如何在硅片中实现它们。

对于传统的ARM,swpswpb指令提供了原子机制。当指令在一个周期内完成时,这似乎很明显。复杂性在于多CPU设计。运行swp的CPU必须锁定总线,以便其他CPU在执行更新时无法读取或写入内存。通常,这将是整个BUS ,而不仅仅是一个位置。 整个BUS 机制意味着Adhmal's law适用。

根据Masta79, Atomic并不意味着“在一个循环中”,是ARM ldrex / strex原子支持的一个显着特征。在ldrex / strex对的持续时间内,特定保留粒度在ARM总线上被锁定。这允许许多不同的复杂无锁原语; ldrex / strex对之间允许使用许多有效说明。但是,它带来了额外的复杂性,strex通过设置的条件代码支持重试状态。这是传统原子操作的思维方式的明确转变。通过特定的预留,如果每个CPU都没有尝试同时锁定相同的保留粒度(特定的一块内存),则每个CPU都可以取得进展。这应该有助于避免 Adhmal路障(也就是带有总线锁定的内存带宽)。

  

当它可以被抢占时如何被称为原子?

代码的一个重要特性是prefetchw(&v->counter);,它将值带入缓存。缓存被视为临时缓冲区,成功的strex将提交它。只有缓存的值才会被修改,直到strex;如果strex发现它是脏的(另一个提交它),那么该值将被丢弃。同一CPU上的中断将执行clrex,这也会使数据无效并使strex重试。