semaphore和mutex的區別?
在看恐龍書的時候一直不是很理解這一塊
Mutex 相比信號量增加了所有權的概念,一隻鎖住的 Mutex 只能由給它上鎖的線程解開,只有系鈴人才能解鈴。Mutex 的功能也就因而限制在了構造臨界區上。
一元信號量則可以由任一線程解開。這樣多出來的一份語義,就是解決讀者-寫者問題的工具。比如某進程讀取磁碟並進入睡眠,等待中斷讀取盤塊結束之後來喚醒它。這就是可以祭出一元信號量的一個情景,而 Mutex 是解決不了的。『信號量』 這個詞本身來自火車站的信號燈,其實本來就暗含著一層 『通知』 的含義。
『同步』這個詞也可以拆開看,一側是等待數據的『事件』或者『通知』,一側是保護數據的 『臨界區』。信號量可以滿足這兩個功能,但是可以注意到兩個功能的應用場景還是蠻大的,有 do one thing and do it best 的空間。linux 內核曾將 semaphore 作為同步原語,後面代碼變得較難維護,刷了一把 mutex 變簡單了不少還變快了,需要『通知』 的場景則替換為了 completion variable。
Goodbye semaphores?
Difference between completion variables and semaphores
How are mutexes and semaphores different with respect to their implementation in a Linux kernel?
Some facts on mutex in Linux.
- only one task can hold the mutex at a time- only the owner can unlock the mutex (unlike the semaphore) - multiple unlocks are not permitted - recursive locking is not permitted (since here count can be maximum 1 unlike the semaphore where for e.g count = 5)- task may not exit with mutex held- memory areas where held locks reside must not be free - mutexes may not be used in hardware or software interrupt contexts such as tasklets and timers
雖然 Mutex和Semaphore 在一定程度上可以互相替代,比如你可以把 值最大為1 的Semaphore當Mutex用,也可以用Mutex+計數器當Semaphore。
但是對於設計理念上還是有不同的,Mutex管理的是資源的使用權,而Semaphore管理的是資源的數量,有那麼一點微妙的小區別。
打個比方,在早餐餐廳,大家要喝咖啡。
如果用Mutex的方式,同時只有一個人可以使用咖啡機,他獲得了咖啡機的使用權後,開始做咖啡,其他人只能在旁邊等著,直到他做好咖啡後,另外一個人才能獲得咖啡機的使用權。如果用Semaphore的模式,服務員會把咖啡做好放到櫃檯上,誰想喝咖啡就拿走一杯,服務員會不斷做咖啡,如果咖啡杯被拿光了,想喝咖啡的人就排隊等著。
Mutex管理的是咖啡機的使用權,而Semaphore管理的是做好的咖啡數量。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和條件鎖的區別:
條件鎖,本質上還是鎖,它的用途,還是圍繞「共享資源」的。條件鎖最典型的用途就是:防止不停地循環去判斷一個共享資源是否滿足某個條件。比如還是買票的例子:我們除了買票的線程外,現在再加一個線程:如果票數等於零,那麼就要掛出「票已售完」的牌子。這種情況下如果沒有條件鎖,我們就不得不在「掛牌子」這個線程里不斷地lock和unlock而在大多數情況下票數總是不等於零,這樣的結果就是:佔用了很多CPU資源但是大多數時候什麼都沒做。另外,假如我們還有一個線程,是在票數等於零時向上級部門申請新的票。同理,問題和上面的一樣。而如果有了條件鎖,我們就可以避免這種問題,而且還可以一次性地通知所有被條件鎖鎖住的線程。這裡有個問題,是關於條件鎖的:pthread_cond_wait 為什麼需要傳遞 mutex 參數?
不清楚條件鎖的朋友可以看一下。總之請記住:條件鎖,是為了避免絕大多數情況下都是lock ---&> 判斷條件 ----&> unlock的這種很佔資源但又不幹什麼事情的線程。它和semaphore的用途是不同的。簡而言之,鎖是服務於共享資源的;而semaphore是服務於多個線程間的執行的邏輯順序的。
請回頭看那個讓大家忘記的廁所例子。我之所以讓大家忘記這個例子,是因為如果你從這個角度去學習semaphore的話,一定會和mutex混為一談。semaphore的本質就是調度線程 ---- 在充分理解了這個概念後,我們再看這個例子。
semaphore是通過一個值來實現線程的調度的,因此藉助這種機制,我們也可以實現對線程數量的限制。例子我就不寫了,如果你看懂了上面的c = a + b的例子,相信你可以輕鬆寫出來用semaphore限制線程數量的例子。而當我們把線程數量限制為1時,你會發現:共享資源受到了保護 ------ 任意時刻只有一個線程在運行,因此共享資源當然等效於受到了保護。但是我要再提醒一下,如果你要對共享資源進行保護,請用mutex;到底應該用條件鎖還是用semaphore,請務必想清楚。通過semaphore來實現對共享資源的保護的確可行但是是對semaphore的一種錯用。
只要你能搞清楚鎖、條件鎖和semaphore為什麼而生、或者說它們是面對什麼樣的設計需求、為了解決什麼樣類型的問題才出現的,你自然就不會把他們混淆起來。
semaphore sem(2); // 同時執行的線程數量上限為2
void toiletA()
{
semaphore_decrease(sem);
// do something
semaphore_increase(sem);
}
void toiletB()
{
semaphore_decrease(sem);
// do something
semaphore_increase(sem);
}
void toiletC()
{
semaphore_decrease(sem);
// do something
semaphore_increase(sem);
}
t1 = thread_create(toiletA);
t2 = thread_create(toiletB);
t3 = thread_create(toiletC);
thread_join(toiletA);
thread_join(toiletB);
thread_join(toiletC);
應該不需要多解釋了。不過要強調一下,雖然semaphore的這種用法和線程池看上去很類似:都是在限制同時執行的線程數量,但是兩者是有本質區別的。
線程池是通過用固定數量的線程去執行任務隊列里的任務來達到避免反覆創建和銷毀線程而造成的資源浪費;而semaphore並沒有直接提供這種機制 ---- 上面的例子中雖然同時最多有兩個線程在運行,但是最一開始三個線程就已經都創建好了;而線程池則是:一開始就創建兩個線程,然後將這三個任務加入到線程池的任務隊列中,讓線程池利用這兩個線程去完成這三個任務。這是恐龍書(和 CSAPP)的敗筆,他先講 semaphore,再把 mutex 當成前者的特例來介紹(其實 mutex 無論從語意上還是實現上都不是 semaphore 的特例)。我認為應該先講 mutex ,再講 condition variable,因為實際開發中這兩個最常用,可以完全替代 semaphore(別抬杠說 signal handler 里只可以用 semaphore),然後在習題或小字里提一句 semaphore 就行了。
Semaphore 與 Mutex 實現不同,但從使用的角度來看 Mutex 的確是 Semaphore 的一種特殊情況(max = 1),用於防止一個資源被多個進程同時使用,而 Semaphore 就有更多的使用場景了,比如可以實現 Condition 來用於生產消費模型等。
雖然都是作為線程同步對象,但是Mutex處在比Semaphore更低級的層次。Mutex 在某些情況下並不能當做Semaphore來用,滿足不了Semaphore的使用情況。但是Mutex加上一個全局整型變數或者成員變數就能實現Semaphore。
很多答案從語意上說了這兩個同步對象的區別,我就從在Windows上這兩者的實現補充一點區別。
當持有Mutex的線程沒有Release就退出的時候,系統會幫你做一次釋放,但是這種釋放和正常調用Release釋放的行為是不一樣的,表現就是Wait函數的返回值
而Semaphore如果不掉調用Release就退出線程,那可用資源數會被繼續佔用。雖然我也忘了,但是,提示一下樓主,手工輸入APUE的例子,跑起來,就自然知道了。
semaphore 是信號量的意思,mutex是其中的一種特殊的信號量,就是初值為1的信號量,叫互斥鎖,一般用來做臨界區的互斥訪問,semaphore的初值可以等於大於0的任何整數,通常等於資源的數量,生產者消費者問題中N個緩衝區的問題中就可以用semaphore Empty=N;
簡單回答:binary semaphore 和 mutex看起來極為相似,但略有不同。
具體答案請看
http://stackoverflow.com/questions/62814/difference-between-binary-semaphore-and-mutex最高票答案。mutex和值為1的信號量差不多
Mutex lock主要是用於critical section, 用來保護shared variable, enforce mutual exclusion.
Semaphore 用途比Mutex廣,semaphore主要分成binary semaphore (counter只有1和0) 和 counting semaphore(counter &> 0)。- Binary semaphore可以實現和mutex lock 差不多的功能,保護critical section, 區別是Lock必須保證release和acquire的是同一個thread/Task,而 semaphore 允許不同thread來執行P和V,這樣就可以用button passing的技巧來防止其他thread的barging。 另外一個區別是multi acquisition lock允許同一個thread多次acquire同一個lock,而一個thread 第二次P同一個Sempahore會被Block。- Counting semaphore 沒有mutual exclusion的功能,但是能用於Synchronization,比如可以用來做bounded buffer 和 Barrier Lock。強烈推薦看這個:進程與線程的一個簡單解釋 - 阮一峰的網路日誌這是阮一峰先生的一篇關於進程與線程的形象化解釋的文章,文章不長,後面講到線程共享時也形象的解釋了semaphore和mutex,看完一下就明白了!閱讀時建議忽略文章里的圖。另外,個人簡單理解是mutex是semaphore=1的特殊情況。
感覺各位高手沒有回答到重點啊。semaphroe是系統調用,每次調用都會陷入內核態。mutex是基於futex的,90%時間都在用戶態,只有出現mutual exclusion的時候才會陷入內核態。所以mutex與semaphore功能相同,但前者的效率比後者高。難道不是么?
高票的那幾個答案真的明白這兩者之間的區別嗎?
A mutex
is essentially the same thing as a binary semaphore and sometimes uses the same basic implementation. The differences between them are in how they are used. While a binary semaphore may be used as a mutex, a mutex is a more specific use-case, in that only the thread that locked the mutex is supposed to unlock it. This constraint makes it possible to implement some additional features in mutexes:- Since only the thread that locked the mutex is supposed to unlock it, a mutex may store the id of thread that locked it and verify the same thread unlocks it.
- Mutexes may provide priority inversion safety. If the mutex knows who locked it and is supposed to unlock it, it is possible to promote the priority of that thread whenever a higher-priority task starts waiting on the mutex.
- Mutexes may also provide deletion safety, where the thread holding the mutex cannot be accidentally deleted.
- Alternately, if the thread holding the mutex is deleted (perhaps due to an unrecoverable error), the mutex can be automatically released.
- A mutex may be recursive: a thread is allowed to lock it multiple times without causing a deadlock.
舉個例子,有一支筆,小明,小華,小戴都要用來寫作業,大家去搶就混亂了,想不混亂因為只有一支,所以同一時間就只有一個人能用,其他人趴在那兒等著,一用完,候著的第一個哥們就搶了繼續用,一直持續下去,這是mutex;
還是這個例子,有一支筆,小明,小華,小戴都需要用,而且還要配合著用來寫作業(有一定的邏輯順序關係),一個人用完了要說一聲,然後後面的人接著用,直至用完,如果不說,那就煩了,後面的人就趴在那一直候著,這是系統工程,大家得聽話,過程很嚴謹,這是semaphore;
上面是一支筆,我們多放點,再來一支,現在是兩支筆,仍然是上面幾個哥們,對於mutex就得兩個筆分的清清楚楚的,搶的人也要分的清清楚楚的,然後再去輪著用;
而對於semaphore,兩支筆是一摸一樣的,用完了說一聲,後面的人拿著先空的筆接著用就完了;
更多筆也是一樣。
以上是一個粗淺的輪廓,理解有限,有錯誤請指正。
從概念上說semaphore比mutex更抽象一些。mutex更偏向實際應用(臨界區保護)。兩者實際是定價,可以相互實現。在一些系統中,是通過sempahore實現mutex,另一些則是通過mutex實現sempahore。
你家恐龍書上不是說了:Semaphore 分兩類,一類叫做mutex semaphore,一類叫做count semaphore。前者value為1,後者value大於1。
在實時系統中,一般互斥鎖會處理優先順序反轉問題,而信號量不會
臨界資源數量是1和n的區別
mutex總是由鎖住它的線程解鎖,初始化為1的semaphore不必。
mutex是 sem 為1的情況。信號量表示現在的資源數。當信號量為1表示這個資源只有1個。mutex就是特別的信號量。
mutex就是數量等於1的semaphore。
前面幾位說了mutex基本可以看做資源只有1的簡化版的信號量,但是mutex有個好處,它是內核級的變數,可以跨進程保護共享數據,有的時候很有用。
推薦閱讀:
※購置筆記本電腦,Ubuntu專用,求品牌型號推薦?
※世界為什麼開發 Linux?
※想學習Linux源碼,哪些方法值得一試?
※在Linux上執行rm -rf操作會導致設備永久變磚嗎?
※為什麼許多EDA工具(如Cadence 和Synopsys)只有Linux版本?