作業系統中的鎖

2021-07-13 21:21:03 字數 2848 閱讀 7244

作業系統內的同步系統,都是使用原子操作實現的。原子操作又是如何實現的呢?

一般的作業系統書都是寫使用二值訊號量實現的。即用二值訊號量擋在原子操作的開始和結束,以保護原子操作不被打斷。這個是重要的理論依據,但並不能指導實踐。因為,二值訊號量其實就是對乙個標誌位置位,當然,在置位前必須測試一下二值訊號量。整個訊號量的獲取過程可以用偽**描述如下:

1. 如果 訊號量s 沒有被置位 那麼 置位訊號量s,訊號量獲取成功;

2. 否則,測試次數或時間到了沒有,如果沒有到則跳轉到步驟一繼續測試;

如果時間或者測試次數到達,則退出訊號量置位。訊號量獲取失敗。

大家仔細看這個過程,如果s是乙個變數的話,需要用if語句判斷一下s,然後再對s置位。不論怎麼說,這個過程都不可能用cpu的一條指令完成,需要很多指令組成,這也就是說,這個二值訊號量的獲取過程有可能被打斷。但理論上說整個執行過程應該是原子的,即不能被分割。我們來分析一下,都是什麼可以打斷這個原子過程。我們猜測可以打斷乙個原子過程的是:

1.中斷

2.其他執行緒

讓我們來分析一下:

1.中斷是肯定可以打斷這個過程的,如果沒有關閉中斷的話,正在置位的時候,就有可能被中斷。如果中斷裡面有對這個訊號量或標誌位有操作的話,那麼可以斷定,這個原子操作不原子了。那豈不是起不到二值訊號量的作用了?是啊,獲取訊號量的時候應該把中斷關了,這個排除這個干擾因素。

2.我們再來看看其他的執行緒,這個問題就相對中斷來講,理解起來比較困難。這至少分為三種情況,一種是cmp/smp的情況;一種是單cpu的情況;最後是asmp的情況。

我們先來看看單cpu的情況,作業系統執行在cpu上,所有的執行緒都執行在該cpu上;只有乙個cpu,那麼cpu的時間資源是輪流分給每個執行緒的。當乙個執行緒需要獲取乙個訊號量時,如果別的執行緒也獲取該訊號量,我們想一想,這種情況是不存在的。因為只有乙個cpu,同一時間只能執行乙個執行緒。必然是序列執行。但是存在這種情況,當第乙個執行緒正在獲取訊號量時,發生了執行緒切換,切換到乙個也獲取該訊號量的執行緒。那麼這個過程就變成不是原子的。那麼這個禁用執行緒切換就好了。各位看官不用著急下這個結論。我們需要考慮乙個問題,什麼情況下才能發生執行緒切換,其實對於單cpu的系統,無外乎兩大類的情況:一種是執行緒自己放棄執行,把cpu的執行權讓給別的執行緒;另外一種是被強迫放棄cpu的執行權。執行緒正在執行乙個原子操作(獲取訊號量),怎麼可能主動放棄cpu的執行權呢?這是不可能的。外界強迫執行緒放棄cpu的執行權倒是有可能:

1.這個執行緒的時間片用完了,必須切換走;

2.中斷退出時,釋放了乙個更高優先順序的執行緒,直接排程到其他執行緒了,沒有回到本執行緒。

實際上這兩種情況都是一樣的,作業系統的時間片是靠中斷計時的。而其他中斷有可能釋放更高優先順序別的任務。分析來分析去,原來發生執行緒切換,也是cpu的中斷引起的,那麼,對於這種情況關中斷就好了。

我們再看看cmp/smp的情況,cmp和smp的情況比較複雜,首先全部的cpu上只執行了乙個作業系統,否則不能視為cmp/smp。假設有兩個cpu的系統,a cpu執行a執行緒,而b cpu執行b執行緒,兩個同時獲取乙個訊號量。這時候關中斷肯定是不奏效的。因為a執行緒只能關閉a cpu的中斷,就算cmp上a 執行緒可以關閉a、b cpu的中斷,但並不能阻止b cpu對b執行緒的執行。更不能阻止b執行緒與a 執行緒競爭訊號量。那怎麼辦?辦法總比問題多:

這裡就採用了乙個很簡單的方法,利用一條cpu的指令完成測試和置位。一條cpu指令,要麼是執行,要麼是不執行,所以必定是原子的。什麼樣的指令才是原子的呢?其實不同cpu架構下有不同的指令,這裡就介紹乙個絕大部分cpu下都有的一條指令,記憶體與暫存器交換指令 xchg。分析如下偽**:

flag = false

reallocate:

xchg s, flag

if (flag == true)

獲取到訊號量

else

沒有獲取的訊號量

goto  reallocate

end if

想象一下,s的初始值為true,如果兩個執行緒先後執行了xchg指令,第乙個執行緒將ture與s值交換,並將s置為false,獲取到訊號量;另外乙個任務用false只能換到false,所以它不能獲取到訊號量。從而實現了鎖。如果多個cpu同時執行交換指令,一般來說,記憶體控制器會進行仲裁,只有乙個cpu能成功交換,其它都不能成功交換。

這個鎖在linux下稱為自旋鎖。自旋的意思是,這段**是忙等的,即cpu的時間不能讓給其他執行緒執行。有些童鞋可能想了,這多浪費,應該讓給其他執行緒執行, :) 其實這個問題也比較複雜,因為作業系統切換執行緒是需要時間的,如果自旋鎖浪費的cpu時間比兩次執行緒切換出去,切換回來的時間還短,那麼,應該選擇自旋鎖。不應該將cpu時間讓出去,否則那是更奢侈的浪費!!!看來,smp/cmp的情況下,鎖的實現方式就有了變化,必須使用一條cpu的指令完成,一般實現的都是忙等。

最後,我們來看看asmp的情況,asmp的話實際上有幾個cpu就跑著幾個相同的作業系統,作業系統之間通過多口ram或著其他的通訊方式通訊。如cmp/smp一樣,a cpu關了中斷並不能影響b cpu的中斷。能不能通過一條指令完成原子操作呢?也是不行的,因為cpu的型號不一樣,同一條指令的執行時間也不一樣。想象一下,乙個慢速的cpu測試成功了鎖,當他寫入的時候,時間較長,在其沒寫入成功時,另外乙個cpu就成功交換了。顯然也不能實現這樣的原子操作。最重要的,如果整個asmp系統中根本就沒有用多口ram實現通訊,那麼也就無法實現xchg指令,更不要談能不能交換成功了。所以這個方法從通用的角度來講,不現實。乙個比較好的辦法是,採用c/s的思路,整個asmp系統有乙個主cpu,如果其他cpu要獲取全域性鎖,利用通訊到主cpu上去仲裁,主cpu去判斷了。這樣,就轉化為乙個cpu上多個執行緒競爭訊號量的問題了。

稍作總結:

單cpu實現鎖是採用關閉中斷的方式;

cmp/smp實現全域性鎖採用自旋鎖+關閉中斷的方式;如果只和本cpu同步,那麼就關中斷好了;如果只和其他cpu同步,採用自旋鎖就可以了;

asmp下實現全域性鎖只需要關閉中斷即可。

作業系統中不同的鎖

鎖是執行緒同步時的乙個重要的工具,然而作業系統中包含了多種不同的鎖,各種鎖之間有什麼不同呢?1 訊號量 semaphore 訊號量分為二元訊號量和多元訊號量,所謂二元訊號量就是指該訊號量只有兩個狀態,要麼被占用,要麼空閒 而多元訊號量則允許同時被n個執行緒占有,超出n個外的占用請求將被阻塞。訊號量是...

作業系統中的鎖的分類

參考 作業系統中的鎖分為兩大類 悲觀鎖和樂觀鎖。1.悲觀鎖 悲觀鎖,pessimistic lock,即這種鎖的 想法 很悲觀 方法執行如果不加鎖就會出事,所以操作必須上鎖,乙個乙個的來。其中重量級鎖 自旋鎖和自適應自旋鎖屬於悲觀鎖。當進入乙個同步 執行緒安全的方法時,需要先獲得該方法的鎖,而退出這...

作業系統專案 鎖

為了作業系統專案,研讀了一下operating systems three easy pieces中關於鎖的那一章,記錄筆記!首先要明確,成為乙個鎖所需具備的條件有 1.提供互斥功能 2.程序排程公平 3.使用鎖時的效能 下面看一下關於鎖的實現的迭代過程 void lock void unlock ...