根据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 }
当它可以被抢占时如何被称为原子
答案 0 :(得分:4)
你似乎完全误解了原子操作是什么。
很明显,如果你看一个值x,看看值是13,然后调用一个使它增加5的atomic_add函数,新结果可能是任何东西,因为另一个线程可能在atomic_add之前更改了值被称为。同样,如果你检查结果,它可能再次是任何东西,因为另一个线程可以改变atomic_add和你的检查之间的结果。
atomic_add函数保证将值增加该量。这就是它的作用。如何实现这一点并不重要。如果有100个线程调用atomic_add(5,& x),则x最终会增加500.这才是最重要的。
这是在ARM和PowerPC等处理器上执行原子操作的典型方法,这些处理器具有保留存储器位置的指令和存储指令,用于检查保留是否仍然存在。
答案 1 :(得分:-1)
ldrex
和strex
采用不同的默认来实现原子指令。传统的compare and swap(简称CAS)在无锁编程方面存在局限性。 load link/store conditional(简称LL / SC)是原子指令的更高级形式,它允许原子链接列表;比较它们并考虑如何在硅片中实现它们。
对于传统的ARM,swp
和swpb
指令提供了原子机制。当指令在一个周期内完成时,这似乎很明显。复杂性在于多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
重试。