- 论坛徽章:
- 0
|
本帖最后由 ycnian 于 2013-09-07 16:29 编辑
大家好,我正在看内核同步部分的代码,但是没有弄清楚原子操作到底是怎么回事。举个例子来说,atomic_add()可以实现原子加操作,代码如下。
static inline void atomic_add(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX "addl %1,%0"
: "+m" (v->counter)
: "ir" (i));
}
其中LOCK_PREFIX定义如下:
#ifdef CONFIG_SMP
#define LOCK_PREFIX_HERE \
".section .smp_locks,\"a\"\n" \
".balign 4\n" \
".long 671f - .\n" /* offset */ \
".previous\n" \
"671:"
#define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
#else /* ! CONFIG_SMP */
#define LOCK_PREFIX_HERE ""
#define LOCK_PREFIX ""
#endif
先不考虑SMP了,只看单处理器的情况,这时候可以直接忽略掉LOCK_PREFIX。这种情况下,我对atomic_add()进行了汇编,结果如下:
00000000 <atomic_add>:
(第1条指令) 0: 55 push %ebp
(第2条指令) 1: 89 e5 mov %esp,%ebp
(第3条指令) 3: 8b 45 0c mov 0xc(%ebp),%eax // 这是v->counter的地址.
(第4条指令) 6: 8b 55 08 mov 0x8(%ebp),%edx // 这是变量i的值
(第5条指令) 9: 8b 4d 0c mov 0xc(%ebp),%ecx // 可能是编译器的问题,这条指令可以忽略
(第6条指令) c: 01 10 add %edx,(%eax) // 求和,并把结果写到v->counter中.
(第7条指令) e: 5d pop %ebp
(第8条指令) f: c3 ret
也就是说atomic_add()汇编的结果是8条指令。假设v的初始值是3,现在两个进程分别执行原子加操作: 进程1 atomic_add(2, v) 进程2 atomic_add(5, v)。
进程1先执行,当执行完第5条指令后发生了进程切换,此时v中的值还是3。进程2接着执行,且中间没有发生进程切换,当进程2执行完毕后v的值变成了8。现在进程1接着执行第6条指令 “add %edx,(%eax)”。寄存器eax中保存的是v的地址,CPU将执行三个操作:1.将v的值读取到寄存器中(现在v的值已经是8了),2.求和(结果是10),3.将v的值写到内存中。这样的话,对于进程1来说,执行atomic_add(2, v)前v的值是3,执行后的值是10了,这还能叫原子操作吗?
不知道是我的理解有误,还是怎么回事?大家怎么理解的?非常感谢。我看的内核版本是3.6.0。
|
|