作業系統 自旋鎖+訊號量+互斥量+臨界區+死鎖的區別
自旋鎖(SpinLock)
自旋鎖是專為防止多處理器併發而引入的一種鎖。如果是單核處理器,則自旋鎖定義為空操作,因為簡單的關閉中斷即可實現互斥。
自旋鎖最多隻能被一個執行緒持有,如果一個執行緒試圖請求一個已被爭用(已被另一個執行緒持有)的自旋鎖,那麼等待自旋鎖的執行緒將會反覆檢查自旋鎖是否釋放,不會進入睡眠狀態,一直處於忙等待狀態(busy-waiting),直到獲取該自旋鎖才能繼續執行未完成的任務,所以常用於短期保護某段程式碼。
另外,持有自旋鎖的程序也不允許睡眠,不然會造成死鎖——因為睡眠可能造成持有鎖的程序被重新排程,而再次申請自己已持有的鎖。
事實上,自旋鎖的初衷就是:在短期間內進行輕量級的鎖定。一個被爭用的自旋鎖使得請求它的執行緒在等待鎖重新可用的期間進行自旋(特別浪費處理器時間),所以自旋鎖不應該被持有時間過長。如果需要長時間鎖定的話, 最好使用訊號量。
自旋鎖的基本形式如下:
spin_lock(&mr_lock);
//臨界區
spin_unlock(&mr_lock);
同一時刻只有一個執行緒允許處於臨界區中,可用來防止多處理器中併發訪問臨界區,搶佔共享資源造成的競爭。
訊號量(Semaphore)
訊號量是一種機制。在進入一個關鍵程式碼段之前,執行緒必須獲取一個訊號量;一旦執行完該關鍵程式碼段,則釋放獲取的訊號量。如果獲取不到訊號量,則進入等待佇列,並保持休眠狀態(sleep-waiting),此時,執行緒釋放佔用的處理器,以便處理器執行其它任務。當有未被持有的訊號量時,喚醒佇列中的執行緒,執行緒從而獲取訊號量,繼續執行未完成的任務。
為了完成上述過程,需要建立一個訊號量signal,然後將Acquire Semaphore signal以及Release Semaphore signal分別放置在每個關鍵程式碼段的首末端。確認這些訊號量signal引用的是初始建立的訊號量。
建立訊號量時即要同時指出允許的最大資源計數和當前可用資源計數。一般是將當前可用資源計數設定為最大資源計數,每增加一個執行緒對共享資源的訪問,當前可用資源計數就會減1,只要當前可用資源計數是大於0的,就可以發出訊號量訊號。但是當前可用計數減小到0時則說明當前佔用資源的執行緒數已經達到了所允許的最大數目,不能在允許其他執行緒的進入,此時的訊號量訊號將無法發出。執行緒在處理完共享資源後,應在離開的同時將當前可用資源計數加1。在任何時候當前可用資源計數決不可能大於最大資源計數。
訊號量基本使用形式為:
static DECLARE_MUTEX(mr_sem);//宣告互斥訊號量
if(down_interruptible(&mr_sem))
//可被中斷的睡眠,當訊號來到,睡眠的任務被喚醒
//臨界區
up(&mr_sem);
訊號量的睡眠特性,使得訊號量可當作鎖來用,特別是臨界區需要被鎖定較長時間(換句話說,需要較長時間持有鎖)的情況;
注:訊號量只能在程序上下文中使用,因為中斷上下文中是不能被排程的;另外當執行緒持有訊號量時,不可以再持有自旋鎖(即針對同一程式碼段,不能同時使用自旋鎖和訊號量機制)。
互斥量(Mutex)
執行緒之間這種因共享資源而產生的相互制約關係。能夠保證多個執行緒對同一共享資源的互斥訪問。
同臨界區有些類似,只有擁有互斥物件(即互斥量)的執行緒才具有訪問共享資源的許可權,由於互斥物件只有一個,因此就決定了任何情況下此共享資源都不會同時被多個執行緒所訪問。當佔據資源的執行緒在任務處理完任務後應釋放佔有的的互斥物件,以便其他執行緒在獲得該互斥物件後得以訪問資源。
使用互斥不僅僅能夠在同一應用程式不同執行緒中實現資源的安全共享,而且可以在不同應用程式的執行緒之間實現對資源的安全共享
互斥量與臨界區的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越程序使用。所以建立互斥量需要的資源更多,所以如果只為了在程序內部是用的話使用臨界區會帶來速度上的優勢並能夠減少資源佔用量。因為互斥量是跨程序的互斥量一旦被建立,就可以通過名字開啟它。
訊號量與互斥量
競爭訊號量與互斥量時需要進行程序睡眠和喚醒,代價較高,所以不適於短期程式碼保護,適用於保護較長的臨界區
互斥量與訊號量的區別?
(1) 互斥量用於執行緒的互斥,訊號量用於執行緒的同步
這是互斥量和訊號量的根本區別,也就是互斥和同步之間的區別
互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的
同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源
(2) 互斥量值只能為0/1,訊號量值可以為非負整數
也就是說,一個互斥量只能用於一個資源的互斥訪問,它不能實現多個資源的多執行緒互斥問題。訊號量可以實現多個同類資源的多執行緒互斥和同步。當訊號量為單值訊號量是,也可以完成一個資源的互斥訪問
(3) 互斥量的加鎖和解鎖必須由同一執行緒分別對應使用,訊號量可以由一個執行緒釋放,另一個執行緒得到
臨界區(Critical Section)
保證在某一時刻只有一個執行緒能訪問關鍵資料的簡便辦法。在任意時刻只允許一個執行緒對共享資源進行訪問。如果有多個執行緒試圖同時訪問同一臨界區,那麼在有一個執行緒進入後其他所有試圖訪問此臨界區的執行緒將被掛起,並一直持續到進入臨界區的執行緒離開。臨界區在被釋放後,其他執行緒可以繼續搶佔,並以此達到用原子方式操作共享資源的目的。
保證在某一時刻只有一個執行緒能訪問資料的簡便辦法。在任意時刻只允許一個執行緒對共享資源進行訪問。如果有多個執行緒試圖同時訪問臨界區,那麼在有一個執行緒進入後,其他所有試圖訪問此臨界區的執行緒將被掛起,並一直持續到進入臨界區的執行緒離開。臨界區在被釋放後,其他執行緒可以繼續搶佔,並以此達到用原子方式操作共享資源的目的。
在使用臨界區時,一般不允許其執行時間過長,只要進入臨界區的執行緒還沒有離開,其他所有試圖進入此臨界區的執行緒都會被掛起而進入到等待狀態,並會在一定程度上影響。程式的執行效能。尤其需要注意的是不要將等待使用者輸入或是其他一些外界干預的操作包含到臨界區。如果進入了臨界區卻一直沒有釋放,同樣也會引起其他執行緒的長時間等待。雖然臨界區同步速度很快,但卻只能用來同步本程序內的執行緒,而不可用來同步多個程序中的執行緒。
死鎖
假設有一個或多個核心任務和一個或多個資源,每個核心都在等待其中的一個資源,但所有的資源都已經被佔用了,也就是說。這便會發生所有核心任務都在相互等待,但它們永遠不會釋放已經佔有的資源,於是任何核心任務都無法獲得所需要的資源,無法繼續執行,這便意味著死鎖發生了。自死瑣是說自己佔有了某個資源,然後自己又申請自己已佔有的資源,顯然不可能再獲得該資源,因此就自縛手腳了。作業系統