【翻譯】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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM