信號量與互斥鎖的區別


之前遇到一個問題,信號量和互斥鎖的區別是什么。一時忘了思考,今天才想到這個問題,翻閱知乎和stackoverflow,理解了之后做簡單整理

一、定義

mutex,互斥鎖,用於序列化對一部分可重入代碼的訪問,這些代碼不能由多個線程同時執行

semaphore,信號量,將共享資源的並發用戶數限制為最大數量

二、使用

Mutex:假設我們有關鍵部分線程T1想要訪問它然后它遵循以下步驟:

  1. 使用關鍵部分
  2. 開鎖

二進制信號量:它基於信令等待和信號工作。等待(s)將“s”值減少一個通常“s”值用值“1”初始化,信號(s)將“s”值增加1。如果“s”值為1表示沒有人使用臨界區,則值為0表示臨界區正在使用中。假設線程T2正在使用臨界區,那么它遵循以下步驟:

  1. wait(s)//最初s值在調用之后等於它的值減1,即0
  2. 使用關鍵部分
  3. signal(s)//現在s值增加,變為1

三、具體分析(引自知乎)

mutex,典型的例子就是買票: 票是共享資源,現在有兩個線程同時過來買票。如果你不用mutex在線程里把票鎖住,那么就可能出現“把同一張票賣給兩個不同的人(線程)”的情況。 我想這個不需要多解釋了。

一般人不明白semaphore和mutex的區別,根本原因是不知道semaphore的用途。 semaphore的用途,一句話:調度線程。 有的人用semaphore也可以把上面例子中的票“保護"起來以防止共享資源沖突,必須承認這是可行的,但是semaphore不是讓你用來做這個的;如果你要做這件事,請用mutex。

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

在這里,我模擬一個最典型的使用semaphore的場景: a源自一個線程,b源自另一個線程,計算c = a + b也是一個線程。(即一共三個線程)

顯然,第三個線程必須等第一、二個線程執行完畢它才能執行。 在這個時候,我們就需要調度線程了:讓第一、二個線程執行完畢后,再執行第三個線程。 此時,就需要用semaphore了。
 
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最典型的用法。 說白了,調度線程,就是:一些線程生產(increase)同時另一些線程消費(decrease),semaphore可以讓生產和消費保持合乎邏輯的執行順序。 而線程池是程序員根據具體的硬件水平和不同的設計需求、為了達到最佳的運行效果而避免反復新建和釋放線程同時對同一時刻啟動的線程數量的限制,這完全是兩碼事。 比如如果你要計算z = a + b +...+ x + y ...的結果,同時每個加數都是一個線程,那么計算z的線程和每個加數的線程之間的邏輯順序是通過semaphore來調度的;而至於你運行該程序的時候到底要允許最多同時啟動幾個線程,則是用線程池來實現的。

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

請回頭看那個讓大家忘記的廁所例子。我之所以讓大家忘記這個例子,是因為如果你從這個角度去學習semaphore的話,一定會和mutex混為一談。semaphore的本質就是調度線程 ---- 在充分理解了這個概念后,我們再看這個例子。

semaphore是通過一個值來實現線程的調度的,因此借助這種機制,我們也可以實現對線程數量的限制。而當我們把線程數量限制為1時,你會發現:共享資源受到了保護 ------ 任意時刻只有一個線程在運行,因此共享資源當然等效於受到了保護。但是我要再提醒一下,如果你要對共享資源進行保護,請用mutex;到底應該用條件鎖還是用semaphore,請務必想清楚。通過semaphore來實現對共享資源的保護的確可行但是是對semaphore的一種錯用

只要你能搞清楚鎖、條件鎖和semaphore為什么而生、或者說它們是面對什么樣的設計需求、為了解決什么樣類型的問題才出現的,你自然就不會把他們混淆起來。

作者:二律背反 鏈接:https://www.zhihu.com/question/47704079/answer/135859188 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM