国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Linux > 正文

Linux中同步互斥機制研究之原子操作

2024-06-28 13:26:16
字體:
來源:轉載
供稿:網友
linux中同步互斥機制研究之原子操作

  操作系統中,對共享資源的訪問需要有同步互斥機制來保證其邏輯的正確性,而這一切的基礎便是原子操作。

| 原子操作(Atomic Operations):

 原子操作從定義上理解,應當是類似原子的,不可再分的操作;然而實際上稍有不同,較為準確的定義應當是:不可被打斷的一個或一系列操作。

  在單處理器系統中,能夠在單條指令中完成的操作都可以認為是“原子操作”,因為中斷只發生在指令邊緣。在多處理器結構中就不同了,由于系統中有多個處理器獨立運行,即使能在單條指令中完成的操作也有可能受到干擾。在X86平臺上,CPU提供了在指令執行期間對總線加鎖的手段。CPU上有一根引線#HLOCK pin連到北橋芯片,如果在匯編程序的指令前面加上前綴"LOCK",經過匯編以后的機器代碼就使CPU在執行這條指令的時候把#HLOCK pin的電位拉低,直到這條指令執行結束時才放開,從而將總線鎖住,這樣同一總線上別的CPU就暫時不能通過總線訪問內存了,保證了這條指令在多處理器環境中對內存訪問的原子性。

| 1. 為什么需要原子操作

  我們來看一個例子,假設我們用兩個線程,完成對全局變量 index 的自增至10的功能,我們這樣寫線程函數:

  

  執行結果如下,可以看到執行了兩次,但結果卻不一樣(不是想象的值為10),事實上每次執行的結果都可能不一樣。理論上,兩個線程分別同時執行5次自增操作,只要執行正確應該總是得到10的結果,但是可以看到兩個線程雖然可以交叉執行,index的值卻不是從1增長到10。圖中mthread程序第一次執行時,線程一將index增加到5后,線程二居然得到了2的結果,這是怎么回事?

  

  我們知道,在計算機中,變量的值是存儲在內存中的,要知道一個存儲在內存中的變量的值就需要讀內存,需要更新這個變量的值就必須寫回去。如果這整個操作是不可打斷的,那么是不會出現上面的結果的,所以中間肯定是出現了什么問題。事實上i++這種操作確實不是原子的,程序編譯成匯編代碼后就可以看到,i++實際上是由Read(讀)-Modify(改)-Write(寫) 3個操作實現的:

  

  

  如上圖所示,兩個線程分別在兩個處理器核上執行,假設i的值剛開始是0,線程1先讀取i的值,放到ax寄存器中,此時線程2也讀取i的值,接著add eax,1,然后回寫到i的地址中,此時i的值為1;之后線程1中再執行add eax,1,再回寫到i的地址,所以i的值就是1,而不是2。如果需要將i++變成原子的就需要一些額外的方式。

| 2. Linux中原子操作的實現

  有了上述的感官認識,現在來說實現就順理成章了。Linux中對原子操作的實現主要在linux-2.6.28/arch/x86/include/asm 目錄下的Atomic_32.h 中,包括了一系列內聯函數(因為這些函數的代碼都不長,基本都采用內嵌匯編代碼編寫)。首先來看原子類型的數據結構 atomic_t的定義:

1 /*2  * Make sure gcc doesn't try to be clever and move things around3  * on us. We need to use _exactly_ the address the user gave us,4  * not some alias that contains the same information.5  */6 typedef struct {7     int counter;8 } atomic_t;

  接著來看如何實現原子操作:

 1 /** 2  * atomic_add - add integer to atomic variable 3  * @i: integer value to add 4  * @v: pointer of type atomic_t 5  * 6  * Atomically adds @i to @v. 7  */ 8 static inline void atomic_add(int i, atomic_t *v) 9 {10     asm volatile(LOCK_PREFIX "addl %1,%0"11              : "+m" (v->counter)12              : "ir" (i));13 }

  上面這段代碼截自Atomic_32.h,即原子的加操作。這個函數的實現采用了內嵌匯編的方式,首先聲明LOCK前綴(實際上是一個宏定義),以原子的方式執行指令addl %1,%0,表示將輸入操作數和輸出操作數編號,將輸入和輸出相加后輸出。其中“+m”中加號表示輸出是可讀可寫的,括號內注明了是原子變量v->counter;m表示輸出存儲在內存之中。“ir”中 i 表示輸入是一個直接操作數,r表示這里輸入 i 是存儲在寄存器中的。

  原子的加有了,原子的減自然也不難:

 1 /** 2  * atomic_sub - subtract integer from atomic variable 3  * @i: integer value to subtract 4  * @v: pointer of type atomic_t 5  * 6  * Atomically subtracts @i from @v. 7  */ 8 static inline void atomic_sub(int i, atomic_t *v) 9 {10     asm volatile(LOCK_PREFIX "subl %1,%0"11              : "+m" (v->counter)12              : "ir" (i));13 }

  其他的原子操作就不舉例了,總之原理就是這樣,在有競爭的訪問中,有時需要保證操作最后執行的邏輯正確性,就必須將某些操作或者指令設置為原子的。原子操作是其他的一些同步互斥機制的基礎,有了原子操作就可以實現多核系統中其他的同步互斥機制了。

參考文獻:

[1].http://edsionte.com/techblog/archives/1809

[2].http://blog.csdn.net/qb_2008/article/details/6840808


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 神木县| 诸城市| 阳城县| 福贡县| 平昌县| 湖口县| 奉节县| 阜城县| 耿马| 铜川市| 永川市| 临清市| 武宣县| 文山县| 民乐县| 龙里县| 阿瓦提县| 安龙县| 厦门市| 页游| 博客| 重庆市| 新泰市| 澄迈县| 探索| 津南区| 中超| 垣曲县| 靖安县| 酒泉市| 定边县| 英山县| 绍兴市| 松阳县| 固原市| 米脂县| 新龙县| 平邑县| 西丰县| 类乌齐县| 黎城县|