為了作業系統專案,研讀了一下operating systems: three easy pieces中關於鎖的那一章,記錄筆記!
首先要明確,成為乙個鎖所需具備的條件有:
1.提供互斥功能
2.程序排程公平
3.使用鎖時的效能
下面看一下關於鎖的實現的迭代過程
void lock()
void unlock()
是用在單處理器作業系統中的,乙個程序在執行就禁止其他程序來打斷。很簡單,但是缺點也很多:
1.若貪心程式或惡意程式佔著鎖不放,唯一能做的就是重啟系統了;
2.不適用於多處理器系統,不同程序執行在不同cpu上,若程序1和程序2都想進入同乙個臨界區,cpu1上的程序1禁用了中斷,但cpu2上並沒有被禁用,還是可以進入臨界區;
3.長時間禁止中斷,可能會丟失中斷現場;
4.效率低下。
typedef struct __lock_t lock_t;
void init(lock_t *mutex)
void lock(lock_t *mutex)
void unlock(lock_t *mutex)
現在假設程序1進入了臨界區,占用了鎖。程序2此時也想進入臨界區,只能在while迴圈中等待,直到程序1呼叫unlock把標誌置為0,才跳出迴圈,進入臨界區。
這種方法不能正確提供互斥功能,在效率上也不高。
1.互斥功能
從flag=0開始。程序1呼叫lock,在跳出迴圈,還沒有把flag寫成1的那一刻,被程序2打斷;程序2呼叫lock(),把flag寫為1,返回中斷;程序1繼續把flag寫為1,這樣兩個程序都進入臨界區了。
2.效率
cpu一直在執行迴圈,其他什麼事也做不了。
int testandset(int *old_ptr, int new)
typedef struct __lock_t lock_t;
void init(lock_t *lock)
void lock(lock_t *lock)
void unlock(lock_t *lock)
為什麼叫test and set呢,是因為讓你在set新值的時候可以test一下舊值!(注意:testandset是屬於硬體支援,以原子方式執行,這裡只是通過c語言**片段去解釋testandset的作用。)
從flag=0開始,程序1呼叫lock(),首先獲取到舊值為0,再把新值1賦給標誌變數,把舊值0返回,這樣程序1就占用了鎖。程序2想要獲取鎖,拿到的舊值是1,就會一直迴圈等待。
注意在單處理器作業系統中,自旋鎖需要搭配搶占式的排程程式使用,不然的話單處理器會一直沉迷迴圈,無法自拔。
1.滿足提供互斥功能
2.無法保證公平性(如果乙個程序一直佔著鎖不放,會出現飢餓現象)
3.在單處理器系統下效率極低;在程序數和cpu數相同的情況下,效率還可以接受
typedef struct __lock_t lock_t;
void lock_init(lock_t *m)
void lock(lock_t *m)
else
} void unlock(lock_t *m)
在程序排程公平性方面,在此處通過等待佇列來控制下乙個獲取鎖的程序,以此避免了飢餓現象;在效能方面,一套操作做完了就把m->guard置零,cpu不會一直被自旋鎖占用,但是無法完全避免自旋,如果你當前一整套拿鎖的操作還沒做完,就被另乙個程序打斷了的話,那個來打斷的程序還是會在那裡自旋的。 作業系統中的鎖
作業系統內的同步系統,都是使用原子操作實現的。原子操作又是如何實現的呢?一般的作業系統書都是寫使用二值訊號量實現的。即用二值訊號量擋在原子操作的開始和結束,以保護原子操作不被打斷。這個是重要的理論依據,但並不能指導實踐。因為,二值訊號量其實就是對乙個標誌位置位,當然,在置位前必須測試一下二值訊號量。...
作業系統中不同的鎖
鎖是執行緒同步時的乙個重要的工具,然而作業系統中包含了多種不同的鎖,各種鎖之間有什麼不同呢?1 訊號量 semaphore 訊號量分為二元訊號量和多元訊號量,所謂二元訊號量就是指該訊號量只有兩個狀態,要麼被占用,要麼空閒 而多元訊號量則允許同時被n個執行緒占有,超出n個外的占用請求將被阻塞。訊號量是...
作業系統要點 2 併發,鎖
作業系統的基本控制原理都是圍繞程序展開的。但是,程序控制的複雜性是由作業系統的併發機制引起的。在支援多道程式環境的通用作業系統中 允許乙個或若十個程序在系統中併發執行,但由於系統硬體資源的有限性,使得併發執行的若干程序之間會出現競爭系統有限軟硬體資源的現象。這些資源包括處理器 記憶體 i 0裝置以及...