linux smp原子操作

原子操作:就是在執行某一操作時不被打斷。

linux原子操作問題來源於中斷、進程的搶佔以及多核smp系統中程序的併發執行。

對於臨界區的操作可以加鎖來保證原子性,對於全局變量或靜態變量操作則需要依賴於硬件平臺的原子變量操作。

因此原子操作有兩類:一類是各種臨界區的鎖,一類是操作原子變量的函數。

對於arm來說,單條彙編指令都是原子的,多核smp也是,因爲有總線仲裁所以cpu可以單獨佔用總線直到指令結束,多核系統中的原子操作通常使用內存柵障(memory barrier)來實現,即一個CPU核在執行原子操作時,其他CPU核必須停止對內存操作或者不對指定的內存進行操作,這樣才能避免數據競爭問題。但是對於load update store這個過程可能被中斷、搶佔,所以arm指令集有增加了ldrex/strex這樣的實現load update store的原子指令。

LDREX和STREX

ARM V7之後的LDREX、STREX指令可以解決這個問題。它保證2個讀-修改-寫序列有交叉的時候,只有1個可以寫成功,另外一個則再次嘗試。

爲在多CPU環境中利用test_and_set指令實現進程互斥,硬件需要提供進一步的支持,以保證test_and_set指令執行的原子性. 這種支持目前多以“鎖總線”(bus locking)的形式提供的

cmpxchg(void* ptr, int old, int new),如果ptr和old的值一樣,則把new寫到ptr內存,否則返回ptr的值,整個操作是原子的

明白了這些,再來看cmpxchgl,在Intel開發文檔上說:
0F B1/r CMPXCHG r/m32, r32 MR Valid Valid* Compare EAX with r/m32. If equal, ZF is set and r32 is loaded into r/m32.Else, clear ZF and load r/m32 into EAX.

翻譯一下:
比較eax和目的操作數(第一個操作數)的值,如果相同,ZF標誌被設置,同時源操作數(第二個操作)的值被寫到目的操作數,否則,清ZF標誌,並且把目的操作數的值寫回eax。

好了,把上面這句話套在cmpxchg上就是:
比較_old和(__ptr)的值,如果相同,ZF標誌被設置,同時_new的值被寫到(__ptr),否則,清ZF標誌,並且把(*__ptr)的值寫回_old。很明顯,符合我們對cmpxchg的理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章