多線程中互斥鎖與信號量的區別

在使用多線程的過程中對於互斥鎖和信號量使用比較迷糊,不知道二者有什麼區別,都能保證線程互斥,現做以下說明:

“信號量是一個線程完成了某一任務就通過信號量告訴別的線程,別的線程再進行某些動作。而互斥鎖是用在多線程多任務互斥的,一個線程佔用了某一個資源,那麼別的線程就無法訪問,直到這個線程unlock,其他的線程纔開始可以利用這 個資源。比如對全局變量的訪問,有時要加鎖,操作完了,在解鎖。有的時候鎖和信號量會同時使用的”
也就是說,信號量不一定是鎖定某一個資源,而是流程上的概念,比如:有A,B兩個線程,B線程要等A線程完成某一任務以後再進行自己下面的步驟,這個任務 並不一定是鎖定某一資源,還可以是進行一些計算或者數據處理之類。而線程互斥量則是“鎖住某一資源”的概念,在鎖定期間內,其他線程無法對被保護的數據進 行操作。在有些情況下兩者可以互換。

針對某一特定流程的話使用信號量,針對某些資源使用,防止多個線程同時操作的話用互斥鎖。

兩者之間的區別:

作用域
信號量: 進程間或線程間(linux僅線程間的無名信號量pthread semaphore
互斥鎖: 線程間,

上鎖時 
信號量: 只要信號量的value大於0,其他線程就可以sem_wait成功,成功後信號量的value減一。若value值不大於0,則sem_wait使得線程阻塞,直到sem_post釋放後value值加一,但是sem_wait返回之前還是會將此value值減一
互斥鎖: 只要被鎖住,其他任何線程都不可以訪問被保護的資源

信號量就相當於燈概念,多個線程都可以點燈,但是一旦燈亮了相當於有信號,別的線程收到這個信號就可以繼續工作,否則就一直等燈亮,如果都沒人點燈燈滅了就都等待燈亮,直到有線程點燈

互斥鎖相當於鎖的概念,一個線程一旦將某個屋子鎖上,別的線程都沒辦法進入該屋子使用其中的東西,只有該線程工作完退出該屋子解鎖,別的線程才能進入。

1. 互斥量用於線程的互斥,信號量用於線程的同步。

這是互斥量和信號量的根本區別,也就是互斥和同步之間的區別。

互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。

同步:是指在互斥的基礎上(大多數情況),通過其它機制實現訪問者對資源的有序訪問。在大多數情況下,同步已經實現了互斥,特別是所有寫入資源的情況必定是互斥的。少數情況是指可以允許多個訪問者同時訪問資源

2. 互斥量值只能爲0/1,信號量值可以爲非負整數。

也就是說,一個互斥量只能用於一個資源的互斥訪問,它不能實現多個資源的多線程互斥問題。信號量可以實現多個同類資源的多線程互斥和同步。當信號量爲單值信號量是,也可以完成一個資源的互斥訪問。

3. 互斥量的加鎖和解鎖必須由同一線程分別對應使用,信號量可以由一個線程釋放,另一個線程得到。

 

動作\系統

Win32

POSIX

創建

CreateSemaphore

sem_init

等待

WaitForSingleObject

sem _wait

釋放

ReleaseMutex

sem _post

試圖等待

WaitForSingleObject

sem _trywait

銷燬

CloseHandle

sem_destroy

int sem_init(sem_t *sem, int pshared, unsigned int value);

sem_init() 初始化一個定位在 sem 的匿名信號量。value 參數指定信號量的初始值。 pshared 參數指明信號量是由進程內線程共享,還是由進程之間共享。如果 pshared 的值爲 0,那麼信號量將被進程內的線程共享,並且應該放置在這個進程的所有線程都可見的地址上(如全局變量,或者堆上動態分配的變量)。

sem_wait() 減小(鎖定)由sem指定的信號量的值.如果信號量的值比0大,
  那麼進行減一的操作,函數立即返回.
  如果信號量當前爲0值,那麼調用就會一直阻塞直到或者是信號量變得可以進行減一的操作
  (例如,信號量的值比0大),或者是信號處理程序中斷調用

sem_trywait() 和 sem_wait()是一樣的,除了如果不能夠對信號量立即進行減一,
  那麼sem_trywait()就會返回一個錯誤(錯誤號是AGAIN)而不是鎖定.
  sem_timedwait() 和 sem_wait()是一樣的,除了如果減一操作不能立即執行的話,
  abs_timeout 指定了調用應該被阻塞的時間限制.
  abs_timeout 參數指向了一個結構體指定了由秒和納秒組成的絕對的超時值:

看一個例子,比如有兩個線程都要往打印機上打東西,但是同一時刻只能打一個。 
那麼首先用sem_init初始化一個信號量,注意pshared表示允許幾個進程共享該信號量,一般設0用於進程內的多線程共享,要看是否支持進程共享,請查看下你的系統的man手冊。 
第三個參數value表示可用的資源的數目,即信號燈的數目,咱們這兒只有1個打印機所以設成1。 
然後線程調用sem_wait取獲取這個信號燈,第一個線程一看,有1個,他就拿到了,然後可以繼續後繼操作,此時信號燈自動減1,變成0個。那麼第二個線程調用sem_wait時就會阻塞在這兒了。 
第一個線程完成打印後,調用sem_post釋放信號燈,信號燈數目變成1,將會喚醒等待的第二個線程,然後第二個線程接着打印。 
最後當所有任務完成後,主線程調用sem_destroy釋放這個信號量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章