2012-01-17 445 views
39

我看到Qt的源一些x86彙編:「鎖」指令在x86彙編中意味着什麼?

q_atomic_increment: 
    movl 4(%esp), %ecx 
    lock 
    incl (%ecx) 
    mov $0,%eax 
    setne %al 
    ret 

    .align 4,0x90 
    .type q_atomic_increment,@function 
    .size q_atomic_increment,.-q_atomic_increment 
  1. 從谷歌搜索,我知道lock指令將導致CPU鎖定總線,但是當CPU釋放總線,我不知道嗎?

  2. 關於整個上面的代碼,我不明白這段代碼如何實現Add

+8

請參閱http://stackoverflow.com/a/3339380/856777 – Lucian 2012-01-17 07:37:58

+0

相關:我的答案[num num可以原子爲'int num'?](https://stackoverflow.com/questions/39393850/can -num-be-atomic-for-int-num)解釋了x86上的原子性,以及'lock'前綴的作用,以及沒有它的情況。 – 2017-09-13 03:47:09

回答

64
  1. LOCK不是指令本身:它是一個指令前綴,它適用於下面的指令。該指令必須的東西做內存(INCXCHGCMPXCHG等)的讀 - 修改 - 寫---在這種情況下,它是incl (%ecx)指令,incecx寄存器中保存的地址rements的l翁詞。

    LOCK前綴確保CPU在操作期間擁有適當緩存行的獨佔所有權,並提供某些額外的訂購保證。這可以通過聲明總線鎖來實現,但CPU會盡可能地避免這種情況。如果總線被鎖定,那麼只有在鎖定指令的持續時間內。

  2. 此代碼複製變量的地址要在堆棧遞增扎進ecx寄存器,然後它lock incl (%ecx)由1原子方式增加該變量接下來的兩個指令設置eax寄存器(其保持的返回值如果變量的新值是0,則返回0,否則返回1。該操作是增量,而不是一個添加(因此名稱)。

+0

因此,指令「mov $ 0,%eax」似乎是多餘的? – gemfield 2012-01-18 03:23:04

+4

@gemfield:不,「MOV」將「EAX」全部設置爲零。 SETNE只改變低字節。如果沒有'MOV','EAX'的3個高字節將包含之前操作的隨機剩餘值,所以返回值不正確。 – 2012-01-18 07:34:15

+0

非常感謝 – gemfield 2012-01-19 02:26:27

10

從谷歌,我知道鎖指令將導致CPU鎖定總線,但我 當CPU釋放總線不知道嗎?

LOCK是一個指令前綴,因此它僅適用於以下指令,源不會使這裏說得很清楚,但真正的指令是LOCK INC。所以總線被鎖定爲增量,然後解鎖

關於整個上面的代碼,我不明白這些代碼 如何實現添加?

他們沒有實現的添加,它們實現的增量,與返回指示一起,如果原來的值是0的除了會使用LOCK XADD(但是,Windows InterlockedIncrement /遞減也與LOCK XADD實現)。

+0

謝謝!那麼哪個寄存器存儲函數的值(q_atomic_increment)的返回值? – gemfield 2012-01-17 08:18:40

+1

返回值存儲在%eax中 – nos 2012-01-17 08:59:17

+0

所以,代碼:「返回q_atomic_increment(_ q_value)!= 0」是檢驗%EAX是否不等於零? – gemfield 2012-01-17 09:15:53

10

你可能不明白的是,增加一個值所需的微碼需要我們先讀取舊值。

Lock關鍵字強制實際發生的多條微指令看起來像原子一樣運行。

如果你有每個試圖增加同一個變量2個線程,他們都在同一時間,然後他們倆增量讀取相同的原始值相同的值,並且他們寫出來的值相同。

代替具有遞增兩次變量,這是典型的期待,你最終一次遞增變量。

鎖定關鍵字防止這種情況的發生。