- 論壇徽章:
- 0
|
本帖最后由 ycnian 于 2013-09-07 16:29 編輯
大家好,我正在看內(nèi)核同步部分的代碼,但是沒有弄清楚原子操作到底是怎么回事。舉個例子來說,atomic_add()可以實現(xiàn)原子加操作,代碼如下。
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()進行了匯編,結(jié)果如下:
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) // 求和,并把結(jié)果寫到v->counter中.
(第7條指令) e: 5d pop %ebp
(第8條指令) f: c3 ret
也就是說atomic_add()匯編的結(jié)果是8條指令。假設(shè)v的初始值是3,現(xiàn)在兩個進程分別執(zhí)行原子加操作: 進程1 atomic_add(2, v) 進程2 atomic_add(5, v)。
進程1先執(zhí)行,當(dāng)執(zhí)行完第5條指令后發(fā)生了進程切換,此時v中的值還是3。進程2接著執(zhí)行,且中間沒有發(fā)生進程切換,當(dāng)進程2執(zhí)行完畢后v的值變成了8,F(xiàn)在進程1接著執(zhí)行第6條指令 “add %edx,(%eax)”。寄存器eax中保存的是v的地址,CPU將執(zhí)行三個操作:1.將v的值讀取到寄存器中(現(xiàn)在v的值已經(jīng)是8了),2.求和(結(jié)果是10),3.將v的值寫到內(nèi)存中。這樣的話,對于進程1來說,執(zhí)行atomic_add(2, v)前v的值是3,執(zhí)行后的值是10了,這還能叫原子操作嗎?
不知道是我的理解有誤,還是怎么回事?大家怎么理解的?非常感謝。我看的內(nèi)核版本是3.6.0。
|
|