按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 }
怎么能叫做原子时,它可以被抢占
你似乎是完全误解的原子操作是什么。
它应该是很明显,如果你看看x的值,看到的值是13,然后调用由5增加它的atomic_add功能,新的结果可能是什么,因为另一个线程可能已经改变了价值atomic_add被称为前。 同样,如果你检查结果,它可能再次成为什么,因为另一个线程可能会改变atomic_add和你之间的检查结果。
一个atomic_add功能保证离开增加通过量的值。 这就是它做什么。 这是如何实现并不重要。 如果百个线程调用atomic_add(5,&x),则x将最终增加了500这是最重要的。
这是原子操作是如何像ARM和PowerPC有一个预留的存储位置和存储指令核对,保留仍然存在的指令的处理器执行的典型方法。
该ldrex
和strex
采取执行原子指令不同的默契。 传统的比较和交换 (CAS的简称)在无锁编程限制。 在装载连杆/条件存储 (简称LL / SC)是原子指令 ,它允许原子链表的更高级形式; 对它们进行比较,并考虑如何他们可能会在硅中实现。
对于传统的臂,所述swp
和swpb
指令提供的原子机制。 随着指令在一个周期内完成这似乎是显而易见的。 并发症是在多CPU设计。 运行在CPU swp
必须锁定总线,使得其它CPU不能读取或为被执行的更新被写入存储器。 通常情况下,这将是整辆巴士 ,而不仅仅是一个单一的位置。 整辆巴士机制意味着Adhmal的法律适用。
按照Masta79, 原子并不意味着“在一个周期”,是ARM的一个显着特点ldrex
/ strex
原子的支持。 一个特别的储备颗粒被锁定的ARM总线上的持续时间ldrex
/ strex
对。 这使得许多不同的复杂的无锁原语; 许多有效的指令允许之间ldrex
/ strex
对。 然而,它配备了额外的复杂性strex
通过条件码被设置支持重试状态。 这是从传统的原子操作的思维定一个明确的转变。 有了具体的保留,可以为每个CPU取得进展,如果他们没有试图锁定在同一时间同一储备granual(内存块特定的)。 这应有助于避免Adhmal路地块 (又名内存带宽,总线锁定)。
怎么能叫做原子时,它可以被抢占?
代码的一个重要特征是prefetchw(&v->counter);
,它带来的价值到缓存中。 高速缓存被当作一个临时的缓冲区和成功strex
将提交。 只有缓存的值被修改,直到strex
; 如果strex
发现它是脏的(另一个提交它),则该值被丢弃。 同样的CPU上的中断都会做clrex
,这也无效数据,使strex
重试。