信號量是一種編程概念,常常用於解決多線程問題。 我對社區的問題: html
什麼是信號量,如何使用? 編程
所以,想象每一個人都在嘗試去洗手間,而洗手間只有必定數量的鑰匙。 如今,若是沒有足夠的鍵,該人須要等待。 所以,能夠將信號量視爲表明可用於浴室(系統資源)的那些鍵集,以供不一樣進程(浴室行進者)請求訪問。 安全
如今想象一下試圖同時去洗手間的兩個過程。 那不是一個好狀況,而且使用信號量來防止這種狀況。 不幸的是,信號量是一種自願機制,過程(咱們的洗手間)能夠忽略它(即,即便有鑰匙,仍然有人能夠將門打開)。 多線程
二進制/互斥量和計數信號量之間也存在差別。 併發
在http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html上查看講義。 工具
構建併發程序有兩個基本概念-同步和互斥。 咱們將看到這兩種類型的鎖(信號燈一般是一種鎖定機制)如何幫助咱們實現同步和互斥。 this
信號量是一種編程結構,可經過實現同步和互斥來幫助咱們實現併發。 信號量有兩種類型,二進制和計數。 spa
信號量包括兩個部分:一個計數器和一個等待訪問特定資源的任務列表。 信號量執行兩項操做:wait(P)[就像獲取鎖同樣],以及release(V)[相似於釋放鎖] –這是一個能夠對信號量執行的僅有的兩項操做。 在二進制信號量中,計數器在邏輯上介於0和1之間。您能夠認爲它相似於具備兩個值的鎖:打開/關閉。 計數信號量具備多個計數值。 操作系統
重要的是要理解,信號量計數器跟蹤沒必要阻塞的任務數量,即它們能夠取得進展。 任務被阻止,而且僅在計數器爲零時纔將其本身添加到信號量列表中。 所以,若是任務沒法進行,則將其添加到P()例程的列表中,而後使用V()例程「釋放」任務。 線程
如今,很明顯地看到如何使用二進制信號量來解決同步和互斥-它們本質上是鎖。
例如 同步:
thread A{ semaphore &s; //locks/semaphores are passed by reference! think about why this is so. A(semaphore &s): s(s){} //constructor foo(){ ... s.P(); ;// some block of code B2 ... } //thread B{ semaphore &s; B(semaphore &s): s(s){} //constructor foo(){ ... ... // some block of code B1 s.V(); .. } main(){ semaphore s(0); // we start the semaphore at 0 (closed) A a(s); B b(s); }
在上面的示例中,B2僅在B1完成執行後才能執行。 假設線程A首先執行-進入sem.P(),而後等待,由於計數器爲0(關閉)。 線程B出現,完成B1,而後釋放線程A-而後完成B2。 所以,咱們實現了同步。
如今,讓咱們看一下帶有二進制信號量的互斥:
thread mutual_ex{ semaphore &s; mutual_ex(semaphore &s): s(s){} //constructor foo(){ ... s.P(); //critical section s.V(); ... ... s.P(); //critical section s.V(); ... } main(){ semaphore s(1); mutual_ex m1(s); mutual_ex m2(s); }
互斥也很是簡單-m1和m2沒法同時進入關鍵部分。 所以,每一個線程都使用相同的信號量爲其兩個關鍵部分提供互斥。 如今,能夠有更大的併發性嗎? 取決於關鍵部分。 (想想還有其餘方法可使用信號量實現互斥..提示提示:我是否只須要使用一個信號量?)
信號量計數:具備多個值的信號量。 讓咱們看看這意味着什麼-一個具備多個值的鎖? 所以,打開,關閉和……嗯。 互斥或同步中的多級鎖有什麼用?
讓咱們更簡單地選擇兩個:
使用計數信號量進行同步:假設您有3個任務-#1和2在3以後要執行。您將如何設計同步?
thread t1{ ... s.P(); //block of code B1 thread t2{ ... s.P(); //block of code B2 thread t3{ ... //block of code B3 s.V(); s.V(); }
所以,若是您的信號量從關閉開始,請確保將t1和t2阻止添加到了信號量列表中。 而後全部重要的t3出現,完成其業務並釋放t1和t2。 他們以什麼順序被釋放? 取決於信號量列表的實現。 能夠是FIFO,能夠基於某些特定的優先級等。 (注意:若是但願以特定順序執行t1和t2,而且不知道信號量的實現,請考慮如何佈置P和V;)
(發現:若是V的數量大於P的數量會發生什麼?)
互斥使用計數信號量:我但願您爲此構建本身的僞代碼(使您更好地理解!)-但基本概念是:counter = N的計數信號量使N個任務能夠自由進入關鍵部分。 這意味着您有N個任務(或線程,若是您願意)進入關鍵部分,可是第N + 1個任務被阻止(進入咱們最喜歡的阻止任務列表),而且只有當有人V成爲信號量時才經過至少一次。 所以,信號量計數器如今再也不在0和1之間擺動,而是在0和N之間擺動,從而容許N個任務自由進出,阻止任何人!
如今,天哪,你爲何須要這麼愚蠢的東西? 互斥的所有目的不是讓一個以上的人訪問資源嗎? (提示提示...您的計算機並不老是隻有一個驅動器,對嗎??)
考慮一下 :是否能夠經過單獨使用計數信號量來實現互斥? 若是您有10個資源實例,而且有10個線程(經過計數信號量)進入並嘗試使用第一個實例怎麼辦?
信號量是一種鎖定資源的方法,能夠確保在執行一段代碼時,只有該段代碼能夠訪問該資源。 這樣能夠防止兩個線程同時訪問資源,這可能會致使問題。
@克雷格:
信號量是一種鎖定資源的方法,能夠確保在執行一段代碼時,只有該段代碼能夠訪問該資源。 這樣能夠防止兩個線程同時訪問資源,這可能會致使問題。
這不只限於一個線程。 能夠將信號量配置爲容許固定數量的線程訪問資源。
邁克爾·巴爾(Michael Barr) 揭祕的互斥量和信號量文章是一個簡短的簡短介紹,介紹了互斥量和信號量不同凡響的緣由以及什麼時候以及不該該使用它們。 我在這裏摘錄了幾個關鍵段落。
關鍵是互斥鎖應用於保護共享資源,而信號燈應用於信令。 一般,您不該使用信號量來保護共享資源,也不該使用互斥體來發信號。 例如,在使用信號量來保護共享資源方面,保鏢類比存在一些問題-您能夠經過這種方式使用它們,但可能會致使難以診斷錯誤。
儘管互斥量和信號量在實現上有一些類似之處,但應始終以不一樣的方式使用它們。
最多見(但仍然不正確)的答案是,互斥量和信號量很是類似,惟一的區別是信號量能夠大於一個。 幾乎全部工程師彷佛都正確地理解了互斥鎖是一種二進制標誌,用於經過確保在代碼的關鍵部份內相互排斥來保護共享資源。 可是,當被問及如何使用「計數信號量」時,大多數工程師(僅憑信心而定)表達了一些教科書的觀點,即它們被用來保護多個等效資源。
...
在這一點上,使用浴室鑰匙做爲保護共享資源(浴室)的想法作出了一個有趣的類比。 若是商店只有一個浴室,那麼一個鑰匙就足以保護該資源並防止多我的同時使用它。
若是有多個浴室,則可能會想像一個浴室那樣對它們進行鍵控並作出多個鍵-這相似於信號燈被濫用。 擁有鑰匙後,您實際上並不知道哪一個浴室可用,若是您沿着這條路走,您可能最終將使用互斥鎖來提供該信息,並確保您不上已被佔用的浴室。
信號量是保護幾個基本相同的資源的錯誤工具,但這是許多人想到並使用它的人。 保鏢的類比明顯不一樣-沒有幾種相同類型的資源,而是有一種資源能夠接受多個同時用戶。 我想能夠在這種狀況下使用信號量,可是在現實世界中不多有此類比喻真正成立的狀況-常常有幾種相同類型,但仍然有個別資源(例如浴室)沒法使用這條路。
...
信號量的正確用法是用於從一個任務向另外一個任務發信號。 互斥鎖應始終由使用它保護的共享資源的每一個任務按此順序獲取和釋放。 相比之下,使用信號量的任務要麼發出信號,要麼等待,而不是同時發出信號或等待。 例如,任務1可能包含用於在按下「電源」按鈕時張貼(即發出信號或遞增信號)特定信號量的代碼,而喚醒顯示器的任務2則懸停在同一信號量上。 在這種狀況下,一個任務是事件信號的產生者; 另外一個消費者。
...
這裏要指出的一點是,互斥鎖會以一種很差的方式干擾實時操做系統,從而致使優先級倒置,因爲資源共享,優先級較低的任務可能會在優先級較高的任務以前執行。 簡而言之,當優先級較低的任務使用互斥鎖搶佔資源A,而後嘗試搶奪B,但因爲B不可用而暫停時,就會發生這種狀況。 在等待期間,出現了一個更高優先級的任務,須要A,可是它已經被捆綁,而且因爲等待B而沒法運行。有不少方法能夠解決此問題,可是一般它是固定的經過更改互斥鎖和任務管理器。 在這種狀況下,互斥鎖比二進制信號量要複雜得多,而且在這種狀況下使用信號量會致使優先級倒置,由於任務管理器沒有意識到優先級倒置而且沒法採起措施對其進行糾正。
...
現代互斥量和信號量之間普遍混淆的緣由是歷史性的,由於它能夠追溯到1974年Djikstra發明的信號量(本文中爲大寫「 S」)。 在此以前,計算機科學家所知的任何中斷安全任務同步和信令機制都沒法有效地擴展以用於兩個以上的任務。 Dijkstra的革命性,安全且可擴展的信號量已應用於關鍵部分保護和信號發送。 因而混亂就開始了。
可是,後來出現了基於優先級的搶佔式RTOS(例如,VRTX,約1980年),創建RMA的學術論文以及由優先級反轉引發的問題以及關於優先級的論文以後,對操做系統開發人員而言這變得顯而易見。在1990年的3繼承協議中,很明顯,互斥鎖不只是帶有二進制計數器的信號量。
互斥體:資源共享
信號量:信號
在未仔細考慮反作用的狀況下,請勿將另外一種藥物用於另外一種藥物。