2019-3-25多線程的同步與互斥(互斥鎖、條件變量、讀寫鎖、自旋鎖、信號量)

信號量和互斥鎖:

信號量(semaphore[ˈseməfɔ:(r)])用在多線程多任務同步的,一個線程完成了某一個動做就經過信號量告訴別的線程,別的線程再進行某些動做。而互斥鎖(Mutual exclusion,縮寫 Mutex)是用在多線程多任務互斥的,一個線程佔用了某一個資源,那麼別的線程就沒法訪問,直到這個線程unlock,其餘的線程纔開始能夠利用這個資源。好比對全局變量的訪問,有時要加鎖,操做完了,在解鎖。儘管兩個概念有點相似,可是他們的側重點不同,信號量不必定是鎖定某一個資源,而是流程上的概念,好比:有A,B兩個線程,B線程要等A線程完成某一任務之後再進行本身下面的步驟,這個任務並不必定是鎖定某一資源,還能夠是進行一些計算或者數據處理之類。而線程互斥量則是「鎖住某一資源」的概念,在鎖按期間內,其餘線程沒法對被保護的數據進行操做。不難看出,mutex是semaphore的一種特殊狀況(n=1時)。也就是說,徹底能夠用後者替代前者。可是,由於mutex較爲簡單,且效率高,因此在必須保證資源獨佔的狀況下,仍是採用這種設計html

Semaphore能夠被抽象爲五個操做:
1.建立 Create,通常初始化一個值n
2.等待 Wait:線程等待信號量,若是值大於0,則得到,值減一;若是隻等於0,則一直線程進入睡眠狀態,知道信號量值大於0或者超時。
3.釋放 Post:執行釋放信號量,則值加一;若是此時有正在等待的線程,則喚醒該線程。
4.試圖等待 TryWait:若是調用TryWait,線程並不真正的去得到信號量,仍是檢查信號量是否可以被得到,若是信號量值大於0,則TryWait返回成功;不然返回失敗。
5.銷燬 Destroy
信號量,是能夠用來保護兩個或多個關鍵代碼段,這些關鍵代碼段不能併發調用。在進入一個關鍵代碼段以前,線程必須獲取一個信號量。若是關鍵代碼段中沒有任何線程,那麼線程會當即進入該框圖中的那個部分。一旦該關鍵代碼段完成了,那麼該線程必須釋放信號量。其它想進入該關鍵代碼段的線程必須等待直到第一個線程釋放信號量。爲了完成這個過程,須要建立一個信號量,而後將Acquire Semaphore VI以及Release Semaphore VI分別放置在每一個關鍵代碼段的首末端。確認這些信號量VI引用的是初始建立的信號量。多線程


 
image.png

進一步說明

通常人不明白semaphore和mutex的區別,根本緣由是不知道semaphore的用途。semaphore的用途,一句話:調度線程。有的人用semaphore也能夠把上面例子中的票「保護"起來以防止共享資源衝突,必須認可這是可行的,可是semaphore不是讓你用來作這個的;若是你要作這件事,請用mutex併發

在網上、包括stackoverflow等著名論壇上,有一個流傳很廣的廁所例子:mutex是一個廁所一把鑰匙,誰搶上鑰匙誰用廁所,誰沒搶上誰就等着;semaphore是多個一樣廁所多把一樣的鑰匙 ---- 只要你能拿到一把鑰匙,你就能夠隨便找一個空着的廁所進去。事實上,這個例子對初學者、特別是剛剛學過mutex的初學者來講很是糟糕 ----- 我第一次讀到這個例子的第一反應是:semaphore是線程池???因此,請務必忘記這個例子。另外,有人也會說:mutex就是semaphore的value等於1的狀況。這句話不能說不對,可是對於初學者來講,請先把這句話視爲錯誤;等你未來完全融會貫通這部分知識了,你才能真正理解上面這句話究竟是什麼意思。總之請務必記住:mutex乾的活兒和semaphore乾的活兒不要混起來post

在這裏,我模擬一個最典型的使用semaphore的場景:a源自一個線程,b源自另外一個線程,計算c = a + b也是一個線程。(即一共三個線程)顯然,第三個線程必須等第1、二個線程執行完畢它才能執行。在這個時候,咱們就須要調度線程了:讓第1、二個線程執行完畢後,再執行第三個線程。此時,就須要用semaphore了。ui

int a, b, c; void geta() { a = calculatea(); semaphore_increase(); } void getb() { b = calculateb(); semaphore_increase(); } void getc() { semaphore_decrease(); semaphore_decrease(); c = a + b; } t1 = thread_create(geta); t2 = thread_create(getb); t3 = thread_create(getc); thread_join(t3); // semaphore的機制我在這裏就不講了,百度一下你就知道。 // semaphore_increase對應sem_post // semaphore_decrease對應sem_wait 

簡而言之,鎖是服務於共享資源的;而semaphore是服務於多個線程間的執行的邏輯順序的。spa

 

 

一:信號量與互斥鎖之間的區別:.net

(1):互斥量用於線程的互斥,信號線用於線程的同步。這是互斥量和信號量的根本區別,也就是互斥和同步之間的區別。線程

(2):互斥量值只能爲0/1,信號量值能夠爲非負整數。設計

也就是說,一個互斥量只能用於一個資源的互斥訪問,它不能實現多個資源的多線程互斥問題。code

信號量能夠實現多個同類資源的多線程互斥和同步。當信號量爲單值信號量是,也能夠完成一個資源的互斥訪問。信號量是經過一個計數器控制對共享資源的訪問,信號量的值是一個非負整數,全部經過它的線程都會將該整數減一。若是計數器大於0,則訪問被容許,計數器減1;若是爲0,則訪問被禁止,全部試圖經過它的線程都將處於等待狀態。

計數器計算的結果是容許訪問共享資源的通行證。所以,爲了訪問共享資源,線程必須從信號量獲得通行證, 若是該信號量的計數大於0,則此線程得到一個通行證,這將致使信號量的計數遞減,不然,此線程將阻塞直到得到一個通行證爲止。當此線程再也不須要訪問共享資源時,它釋放該通行證,這致使信號量的計數遞增,若是另外一個線程等待通行證,則那個線程將在那時得到通行證。

(3):互斥量的加鎖和解鎖必須由同一線程分別對應使用,信號量能夠由一個線程釋放,另外一個線程獲得。

 

二:互斥和同步的定義

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

同步:是指在互斥的基礎上(大多數狀況),經過其它機制實現訪問者對資源的有序訪問。在大多數狀況下,同步已經實現了互斥,特別是全部寫入資源的狀況一定是互斥的。少數狀況是指能夠容許多個訪問者同時訪問資源。

 

三:深刻解剖互斥量和信號量

互斥量(Mutex):
Mutex本質上說就是一把鎖,提供對資源的獨佔訪問,因此Mutex主要的做用是用於互斥。Mutex對象的值,只有0和1兩個值。這兩個值也分別表明了Mutex的兩種狀態。值爲0, 表示鎖定狀態,當前對象被鎖定,用戶進程/線程若是試圖Lock臨界資源,則進入排隊等待;值爲1,表示空閒狀態,當前對象爲空閒,用戶進程/線程能夠Lock臨界資源,以後Mutex值減1變爲0。

Mutex能夠被抽象爲四個操做:

建立 Create

加鎖 Lock

解鎖 Unlock

銷燬 Destroy

信號量:

信號量(Semaphore),有時被稱爲信號燈,是在多線程環境下使用的一種設施, 它負責協調各個線程, 以保證它們可以正確、合理的使用公共資源。

Semaphore能夠被抽象爲五個操做:

建立 (CreateSemaphore / sem_init)

等待    (WaitForSingleObject / sem _wait)

釋放 (ReleaseMutex / sem _post)

試圖等待 (WaitForSingleObject / sem _trywait)

銷燬 (CloseHandle / sem_destroy)

參考

1.https://www.zhihu.com/question/47704079
2.https://www.cnblogs.com/alinh/p/6905221.html

3.https://blog.csdn.net/daaikuaichuan/article/details/82950711#font_size5font_347

相關文章
相關標籤/搜索