【翻譯】InterlockedIncrement內部是如何實現的?

    Interlocked系列函數能夠對內存進行原子操做,它是如何實現的?
    它的實現依賴於底層的CPU架構。對於某些CPU來講,這很簡單,例如x86能夠經過 LOCK前綴直接支持Interlocked操做(有一個額外的特性就是XCHG指令老是隱式包含了LOCK前綴)。IA64和x64也直接支持原子的load-modify-store操做。
    其它的多數CPU架構把這個操做分紅兩部分,被稱爲 Load-link/store-conditional。第一部分(load-link)從指定內存地址讀取一個值,而且處理器會監視這個內存地址,看是否有其它處理器修改該值。第二部分(store-conditional)是若是這期間沒有其它處理器修改該值,則將新值存回該地址。所以,一個原子的load-link/store-conditional操做就是經過load-link讀取值,進行一些計算,而後試圖store-conditional。若是store-conditional失敗,那麼從新開始整個操做。
 1 LONG InterlockedIncrement( LONG volatile *value )
 2 {
 3     LONG        lOriginal, lNewValue;
 4     do
 5     {
 6         //
 7         //經過load-link讀取當前值
 8         //能夠知道寫回以前是否有人修改它
 9         //
10         lOriginal = load_link(value);
11  
12         //
13         //計算新的值
14         //
15         lNewValue = lOriginal + 1;
16  
17         //
18         //有條件的寫回新值
19         //若是有人在計算期間覆寫該值,則函數返回失敗
20         //
21     } while ( !store_conditional(value, lNewValue));
22     return lNewValue;
23 }
(若是看起來有些熟悉,是的,你以前見到過這種模式。)
    請求CPU監視一個內存地址依賴於CPU本身的實現。但要記住一件事情,CPU在同一時間只能監視一個內存地址,而且這個時間是很短暫的。若是你的代碼被搶佔了或者在load-link後有一個硬件中斷到來,那麼你的store-conditional將會失敗,由於CPU由於硬件中斷而分心了,徹底忘記了你要求它監視的內存地址(即便CPU成功的記住了它,也不會記過久,由於硬件中斷幾乎都會執行本身的load-link指令,所以會替換成它本身要求監視的內存地址)。
    另外,CPU可能會有點懶,在監視時並不監視內存地址,而是監視cache line,若是有人修改了一個不一樣的內存位置,可是恰好跟要被監視的內存地址在同一個cache line裏,store-conditional操做也會失敗,即便它事實上能夠成功完成。ARM架構的CPU是太懶了,以致於任何向同一塊2048字節寫入的操做都會致使store-conditional失敗。
    這對於須要用匯編語言來實現Interlocked操做的你來講意味着什麼?你須要儘量減小load-link和store-conditional之間的指令數。例如,InterlockedIncrement只不過是給值加1。你在load-link和store-conditional之間插入的指令越多,store-conditional失敗的可能就越大,你就不得不重來一次。若是你在二者之間插入的指令太多了就會致使store-conditional永遠不會成功。舉一個極端的例子,若是你計算新值的代碼須要耗時5秒,在這5秒內確定會接收到不少硬件中斷,store-conditional操做就永遠都會失敗。
 
本文譯自The Old New Thing,原文地址http://blogs.msdn.com/b/oldnewthing/archive/2013/09/13/10448736.aspx
相關文章
相關標籤/搜索