訊號量和互斥鎖

2021-07-05 03:17:03 字數 3014 閱讀 2135

概念

訊號量用在多執行緒多工

同步的,乙個執行緒完成了某乙個動作就通過訊號量告訴別的執行緒,別的執行緒再進行某些動作(大家都在sem_wait的時候,就阻塞在那裡)。

互斥鎖是用在多執行緒多工

互斥的,乙個執行緒占用了某乙個資源,那麼別的執行緒就無法訪問,直到這個執行緒unlock,其他的執行緒才開始可以利用這個資源。比如對全域性變數的訪問,有時要加鎖,操作完了,再解鎖。

有的時候鎖和訊號量會同時使用的.  

也就是說,訊號量不一定是鎖定某乙個資源,而是流程上的概念,比如:有a,b兩個執行緒,b執行緒要等a執行緒完成某一任務以後再進行自己下面的步驟,這個任務並不一定是鎖定某一

資源,還可以是進行一些計算或者資料處理之類。而執行緒互斥量則是「鎖住某一資源」的概念,在鎖定期間內,其他執行緒無法對被保護的資料進行操作。在有些情況下兩者可以互換。

作用域

訊號量: 程序間或執行緒間

互斥鎖: 執行緒間

上鎖時

訊號量: 只要訊號量的value大於0,其他執行緒就可以sem_wait成功,成功後訊號量的value減一。若value值不大於0,則sem_wait阻塞,直到sem_post釋放後value值加一。一句話

,訊號量的value>=0。

互斥鎖: 只要被鎖住,其他任何執行緒都不可以訪問被保護的資源。如果沒有鎖,獲得資源成功,否則進行阻塞等待資源可用。一句話,執行緒互斥鎖的vlaue可以為負數。

linux實現

- 訊號量

維護訊號量狀態的是linux核心作業系統而不是使用者程序。我們可以從頭檔案/usr/src/linux/include/linux/sem.h 

中看到核心用來維護訊號量狀態的各個結構的定義。訊號量是乙個資料集合,使用者可以單獨使用這一集合的每個元素。要呼叫的第乙個函式是semget,用以獲

得乙個訊號量id。

struct

semaphore

;

從以上訊號量的定義中,可以看到訊號量底層使用到了spin_lock的鎖定機制,這個spin_lock主要用來確保對count成員的原子性的操作(count--)和測試(count > 0)。

訊號量的p操作:

(1).void down(struct semaphore *sem);

(2).int down_interruptible(struct semaphore *sem);

(3).int down_trylock(struct semaphore *sem);

- 互斥鎖

struct

mutex

;

自旋鎖

自旋鎖,是為實現保護共享資源而提出一種鎖機制。

其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能有乙個保持者,也就說,在任何時刻最多只能有乙個執行單元獲得鎖。但是兩者在排程機制上略有不同。對於互斥鎖,如果資源已經被占用,資源申請者只能進入睡眠狀態。但是自旋鎖不會引起呼叫者睡眠,如果自旋鎖已經被別的執行單元保持,呼叫者就一直迴圈在那裡看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。

自旋鎖一般原理

跟互斥鎖一樣,乙個執行單元要想訪問被自旋鎖保護的共享資源,必須先得到鎖,在訪問完共享資源後,必須釋放鎖。如果在獲取自旋鎖時,沒有任何執行單元保持該鎖,那麼將立即得到鎖;如果在獲取自旋鎖時鎖已經有保持者,那麼獲取鎖操作將自旋在那裡,直到該自旋鎖的保持者釋放了鎖。由此我們可以看出,自旋鎖是一種比較低階的保護資料結構或**片段的原始方式,這種鎖可能存在兩個問題:死鎖和過多占用cpu資源。 

自旋鎖適用情況

自旋鎖比較適用於鎖使用者保持鎖時間比較短的情況。正是由於自旋鎖使用者一般保持鎖時間非常短,因此選擇自旋而不是睡眠是非常必要的,自旋鎖的效率遠高於互斥鎖。訊號量和讀寫訊號量適合於保持時間較長的情況,它們會導致呼叫者睡眠,因此只能在程序上下文使用,而自旋鎖適合於保持時間非常短的情況,它可以在任何上下文使用。如果被保護的共享資源只在程序上下文訪問,使用訊號量保護該共享資源非常合適;如果對共享資源的訪問時間非常短,自旋鎖也可以。但是如果被保護的共享資源需要在中斷上下文訪問(包括底半部即中斷處理控制代碼和頂半部即軟中斷),就必須使用自旋鎖。自旋鎖保持期間是搶占失效的,而訊號量和讀寫訊號量保持期間是可以被搶占的。自旋鎖只有在核心可搶占或smp(多處理器)的情況下才真正需要,在單cpu且不可搶占的核心下,自旋鎖的所有操作都是空操作。另外格外注意一點:自旋鎖不能遞迴使用。

自旋鎖實現

typedef

struct

spinlock

;

#endif

};

}

spinlock_t

;

訊號量/互斥體和自旋鎖的區別

訊號量/互斥體允許程序睡眠屬於睡眠鎖,自旋鎖則不允許呼叫者睡眠,而是讓其迴圈等待,所以有以下區別應用 

1)、訊號量和讀寫訊號量適合於保持時間較長的情況,它們會導致呼叫者睡眠,因而自旋鎖適合於保持時間非常短的情況

2)、自旋鎖可以用於中斷,不能用於程序上下文(會引起死鎖)。而訊號量不允許使用在中斷中,而可以用於程序上下文

3)、自旋鎖保持期間是搶占失效的,自旋鎖被持有時,核心不能被搶占,而訊號量和讀寫訊號量保持期間是可以被搶占的

另外需要注意的是

1)、訊號量鎖保護的臨界區可包含可能引起阻塞的**,而自旋鎖則絕對要避免用來保護包含這樣**的臨界區,因為阻塞意味著要進行程序的切換,如果程序被切換出去後,另一程序企圖獲取本自旋鎖,死鎖就會發生。

2)、在你占用訊號量的同時不能占用自旋鎖,因為在你等待訊號量時可能會睡眠,而在持有自旋鎖時是不允許睡眠的。

訊號量,互斥鎖

注 摘自 程式設計師的自我修養 相關章節。關鍵字 執行緒同步 原子操作 鎖 二元訊號量 訊號量 互斥量 臨界區 讀寫鎖 條件變數 原子操作 共享資料 全域性變數或堆變數 的自增 操作在多執行緒環境下會出現錯誤是因為這個操作 一條c語句 被編譯為彙編 後不止一條指令,因此在執行的時候可能執行了一半就被...

訊號量 互斥鎖

訊號量與普通整型變數的區別 訊號量 semaphore 是非負整型變數,除了初始化之外,它只能通過兩個標準原子操作 wait semap signal semap 來進行訪問 操作也被成為pv原語 p 於dutch proberen 測試 v 於 dutch verhogen 增加 而普通整型變數則...

POSIX訊號量和互斥鎖

1 建立訊號量 sem t sem open const char name,int oflag sem t sem open const char name,int oflag,mode t mode,unsigned int value 功能 初始化有名訊號量 int sem init sem ...