精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

進程同步機制:為進程并發執行保駕護航

開發 后端
本文是對進程同步機制的一個大總結(9000+字吐血總結),涵蓋面非常的全,包括了進程同步的一些概念、軟件同步機制、硬件同步機制、信號量機制和管程機制,對每種機制結合代碼做了詳細的介紹,并且對瑣碎的知識點和概念解釋的非常清晰。

本文是對進程同步機制的一個大總結(9000+字吐血總結),涵蓋面非常的全,包括了進程同步的一些概念、軟件同步機制、硬件同步機制、信號量機制和管程機制,對每種機制結合代碼做了詳細的介紹,并且對瑣碎的知識點和概念解釋的非常清晰。

​在前面的博客中講述了進程的狀態及其狀態的轉換,每種狀態的含義和轉換的原因。同樣我們也知道,在OS引入了進程后,可以使系統中的多道程序可以并發的執行,進程的并發執行一方面極大的提高了系統的資源利用率和吞吐量,但是另一方面卻使系統變得更加復雜,如果不能采取有效的措施,對多個進程的并發執行進行妥善的管理,必然會因為這些進程對系統資源的無序爭奪給系統造成混亂,致使每次的處理結果顯現出不可再現性。

​對于上面的問題,大家想一想這么一個場景,如果我們在買火車票(just for 舉栗子)時,沒有排隊這個機制,大家亂糟糟的圍在售票員旁邊,手里舉著錢大叫來一張到xxx的硬座、來張到xxx的臥鋪。。。咦,不寒而栗、可怕、腦殼痛。但是如果我們有序的排隊購票,大家就都可以快速的買到自己想要的通往幸福的車票。

[[283320]]

​進程同步機制就是這么一個保障OS中多個進程能夠有條不紊的運行的“規則”。本文中,我們將會詳細的介紹幾種進程同步機制。(本章中所講的OS是單處理機系統,多處理機系統中的情況過于復雜,不利于理解)

1、進程同步的幾個重要概念

​進程同步機制的主要任務,是對多個相關的進程在執行次序上進行協調,使并發執行的諸多進程之間能夠按照一定的規則共享系統資源,并能很好的相互合作,從而是程序之間的執行具有可再現性。

​進程間的兩種制約關系:

  1. 間接相互制約(互斥):因為進程在并發執行的時候共享臨界資源而形成的相互制約的關系,需要對臨界資源互斥地訪問;
  2. 直接制約關系(同步):多個進程之間為完成同一任務而相互合作而形成的制約關系。

​臨界資源只同一時刻只允許一個進程可以訪問的資源稱之為臨界資源,諸進程之間應采取互斥方式,實現對臨界資源的共享。比如打印機、磁帶機等都是臨界資源。我們通過打印機來說明為什么臨界資源同一時刻只允許一個進程使用,假設同一時刻A、B進程同時訪問打印機,兩個進程同時執行打印任務,因為進程的并發性,最后可能導致的就是打印機打出來的內容就是混雜著兩方的文字,這樣得到的打印結果既不是A進程想要的也不是B進程想要的,只會造成資源的浪費。

​臨界區:進程中訪問臨界資源的那段代碼。顯然若能保證諸進程互斥的進入自己的臨界區,便可實現進程間對臨界資源的互斥訪問。因為每個進程每個進程在進入臨界區之前,應先對欲訪問的臨界資源的“大門”狀態進行檢測(主要檢查該臨界資源是否有進程正在訪問,如果此時臨界資源未被訪問,對應的“大門”是敞開的狀態),如果“大門”敞開,進程便可進入臨界區,并將臨界區的“大門”關上;否則就表示有進程在臨界區內,當前進程無法進入臨界區。

​指令:指令就是機器語言的一個語句,它是一組有意義的二進制代碼。因為是機器語言的一條指令,所以指令就可以等價于是原子性的,只有在執行完一條指令后才會去響應中斷(如果有的話)。

​原語:由若干條指令組成的,用戶完成一定功能的一個過程。原語操作的一個特點就是“原子操作”,因此原語在執行的過程中不允許被中斷。原子操作在系統態下執行,常駐內存。

​同步機制應遵循的規則:

  1. 空閑讓進:當臨界區的“大門”敞開時,應當允許一個請求的進入臨界區的進程立即進入臨界區;
  2. 忙則等待:當臨界區的“大門”關閉時,因而其他試圖進入臨界區的進程必須等待,以保證對臨界資源的互斥訪問;
  3. 有限等待:對要求進入臨界區的進程,應保證在有限的時間能進入自己的臨界區,一面陷入“死等”狀態;
  4. 讓權等待:當進程不能進入自己的臨界區時,應立即釋放處理機,以免進程陷入“忙等”狀態。

​在這里解釋一下“死等”和“忙等”兩個狀態,因為這兩個狀態在我們看來似乎是沒有什么區別的,比如“死等”和“忙等”都是沒能進入臨界區,那兩者的區別到底是什么呢?

  1. 死等:首先對于“死等”的進程來說,這個進程可能是處于阻塞狀態,等著別的進程將其喚醒(Signal原語),但是喚醒原語一直無法執行,對于阻塞的進程來說,就是一直處于“死等”(睡死了,沒有人喊你起床)的狀態了,并且在死等狀態,是沒有獲得處理機的;
  2. 忙等:忙等狀態比較容易理解,處于忙等狀態的進程是一直占有著處理機去不斷的判斷臨界區是否可以進入,在此期間,進程一直在運行(忙死了都,但是都是白忙),這也就是“忙等”狀態,有一點需要注意的是,在單處理機系統中,忙等是非常可怕的,因為處于忙等的進程會一直霸占著處理機(不會去釋放處理機,發生了忙等的單CPU OS,無法執行別的進程,除非系統重啟,即忙等的狀態在單CPU系統中是無法被打破的)。

​其實不管是“忙等”還是“死等”,都是對OS有害的,都是應該努力避免的。

​進程的同步機制包含軟件同步機制、硬件同步機制、信號量機制、管程機制等,也就是這些機制,可以保證程序并發執行時的可再現性。

2、軟件同步機制

​其實說到使用軟件來實現同步機制,大家想到的最多的應該就是Java多線程了,Java通過鎖、synchronized、信號量等機制實現了線程的同步,但是線程間是共享父進程中的所有資源的,就比如多個職員坐在一間辦公室里,大家可以面對面的交談,這樣可以方便的解決共享資源的問題;但是在線程之間(就像是分布在世界各地的多個辦公室),如果需要共享系統資源時,進程之間很難直接通過軟件來進行交流,對系統資源的互斥共享就很麻煩了,需要借助硬件資源來完成同步了,需要在內存中單獨使用一塊區域來保存進程是否在臨界區內的標志。

​ 我們先來看下面一段代碼: 

  1. //inside1、inside2是進程P1和P2在內存中保存的標志,表示進程是否在臨界區內  
  2. inside1 = false 
  3. inside2 = false 
  4. //進程P1  
  5. process P1  
  6. begin  
  7. while(inside2) ; //循環測試  
  8. inside1 := true 
  9. 臨界區;  
  10. inside1 := false 
  11. end 
  12. //進程P2  
  13. process P2  
  14. begin  
  15. while(inside1) ; //循環測試  
  16. inside2 := true 
  17. 臨界區;  
  18. inside2 := false 
  19. end

​代碼邏輯很清晰,就是進程P1或者P2想進入臨界區之前,先去判斷對方是否在臨界區內,如果在的話,就一直循環等待,否則就進入臨界區,然后“關門”(掛鎖)。第一眼看似乎是沒什么問題,但是如果進程在執行期間,比如P1先執行,在執行掛鎖(inside1 = true)之前,發生了中斷,進程P2也開始了執行,此錢P1的鎖還沒有掛上,因此進程P2可以進入臨界區,在臨界區內執行的時候,P2也發生了中斷,P1恢復執行,因為之前已經執行過判斷是否可以進入臨界區的代碼,因此此時同樣的可以進入臨界區,在這種情況下,兩個進程同時的進入了臨界區,進程的執行就會出現錯誤。

​雖然在上面的進程P1和P2執行的過程中發生了很多恰巧的事(小概率事件),P1在掛鎖前中斷、P2在臨界區執行時中斷、P1和P2進程能在對方在中斷時搶占CPU,這幾個事件組合在一起,概率就更加的小了,但是仍然的是存在問題的。

​這個時候你可能會想,我在判斷之前先掛上鎖呢,我們把代碼的順序調整一下,大家請看: 

  1. //...  
  2. //進程P1  
  3. process P1  
  4. begin  
  5. inside1 := true 
  6. while(inside2) ; //循環測試  
  7. 臨界區;  
  8. inside1 := false 
  9. end 
  10. //進程P2  
  11. process P2  
  12. begin  
  13. inside2 := true 
  14. while(inside1) ; //循環測試  
  15. 臨界區;  
  16. inside2 := false 
  17. end

​這樣的話,進程P1、P2在并發執行的時候就沒有問題了么,我們來看這樣一種情況,P1先執行,掛鎖成功,假設在成功之后,P1發生了中斷,進程P2開始執行,此時P2同樣可以掛鎖,但是在判斷是否可以進入臨界區時,則無法成功,會一直在循環中判斷,當P1再次恢復執行時,尷尬的事情發生了,P1也無法進入臨界區了,因為P2同樣把鎖給掛上了。

​上面是兩種軟件同步機制的實現,第一個是雙標志法先檢查,第二個是雙標志法后檢查,但是兩個方法都無法真正的解決進程同步問題。雙標志法先檢查法可能會讓兩個進程同時進入臨界區,雙標志法后檢查法可能會讓兩個進程都無法進入臨界區,形成死鎖問題。

​雖然通過軟件方式也可以實現諸進程互斥的進入臨界區的問題,比如Peterson算法,但是有一定的難度,并且存在很大的局限性,因而現在已經很少使用了,下面我們來看下別的幾種方式。

3、硬件同步機制

​我們在軟件同步機制里講的兩個例子,都是在落鎖和判斷之間發生中斷,乃至導致無法實現互斥的進入臨界區,那么,我們是不是可以在這個期間不允許發生中斷呢?這個就需要用到硬件了,下面我們就一起來看一下。

3.1 關中斷

​這個方法就非常之霸氣了,進程在落鎖和判斷之間不是有可能會發生中斷么,那么我在開始測試之前關閉中斷(OS內核不響應中斷信號),到測試并上鎖之后在打開中斷。這樣可以保證兩個操作之間的連續性,保證臨界資源的互斥訪問。

​但是關中斷也必然會存在許多缺點:1.濫用關中斷的權利可能導致嚴重后果;2.關中斷時間過長會影響系統的并發性,直接的影響系統的資源利用率;3.關中斷無法適應多CPU系統(多CPU系統不在本文的討論范圍內)

3.2 測試并建立(Test-and-Set, TS)指令

​我們使用關中斷來解決落鎖和判斷之間不允許響應中斷,但是我們如果把這兩個執行變成一條指令呢,這樣是不是就可以保證中斷不會再落鎖和判斷之間被響應?

​我們可以借助一條硬件指令-----“測試并建立”指令TS(Test-and-Set),來實現臨界資源的互斥訪問。TS指令的一般性描述如下: 

  1. //TS指令  
  2. boolean TS(boolean *lock){  
  3. if(*lock == false){  
  4. *lock = true 
  5. return true 
  6. }else 
  7. return false 
  8.  
  9.  
  10. //內存中保存的鎖的值  
  11. boolean lock;  
  12. lock = false; //臨界區可以進入  
  13. //進程P1,P2,P3...Pn  
  14. process Pi{  
  15. //...  
  16. while(!TS(&lock));//循環請求鎖  
  17. 臨界區;  
  18. lock = false;//解鎖,歸還臨界資源  

​我們可以把TS指令看成上面的TS函數的執行過程,其執行過程是不可分割的,即是一條原語。當lock的值為false時,表示臨界資源空閑,當lock的值為true時,表示該資源正在被使用。

​使用TS指令來管理臨界區時,需要為每個臨界資源設置一個布爾變量lock。當有進程需要進入臨界區時,需要先用TS指令測試臨界區對應的那把“鎖”,如果返回true,臨界區空閑,可以進入,并落鎖,阻止別的進程再進入臨界區;如果TS返回false,則必須要循環請求,直到TS返回的值變為true。

3.3 對換指令

​該指令也稱為swap指令,用于交換兩個字的內容,其處理過程描述如下: 

  1. void swap(boolean *a, boolean *b){  
  2. boolean tmp;  
  3. tmp = *a;  
  4. *a = *b;  
  5. *b = tmp;  
  6.  
  7. //內存中保存的鎖的值  
  8. boolean lock;  
  9. lock = false; //臨界區可以進入  
  10. //進程P1,P2,P3...Pn  
  11. process Pi{  
  12. //...  
  13. boolean key = true 
  14. do{  
  15. swap(&lock, &key);  
  16. }while(key != false)//循環請求鎖  
  17. 臨界區;  
  18. lock = false;//解鎖,歸還臨界資源  

​Swap指令和TS指令類似,也需要為每個臨界資源設置一個布爾變量lock,不同的在進程中使用一個局部變量Key字段去替換出lock中的值,通過判斷key的值就可以判斷臨界資源是否空閑。

​有一點需要注意的,因為原語是將多個指令合并成一個指令,在原語的執行過程中也是不響應中斷的,使之成為原子操作,這個期間,等于是屏蔽中斷,也就等價于我們講的第一種硬件方式—關中斷,因此原語操作的指令長度應該是短小精悍的,這樣才能保證系統的效率。

​利用上述的硬件指令能有效的實現進程的互斥,但是當資源忙碌時,其他訪問進程的必須不斷的進程測試,處于一種“忙等”的狀態,違背了讓權等待的原則,造成處理機時間的浪費,同時也很難將它們用于解決復雜的進程問題。

4、信號量機制

​信號量機制是1965年迪杰斯特拉(Edsger Wybe Dijkstra)提出的一種卓有成效的進程同步工具。信號量機制在長期的應用中得到了很大的發展,從整型信號量經記錄型信號量,進而發展為“信號量集”機制,在目前來講,信號量。

​需要著重說明的一點是:信號量除了初始化外,僅能被通過兩個標準的原子操作wait(S)和signal(S)來訪問,這兩個操作也被稱為P、V操作,這幾個操作都是原語操作。

4.1 整型信號量

​整型信號量是最開始由迪杰斯特拉定義的,整型信號量也很簡單,里面只有一個表示資源的數量的整形量,一般使用S符號來表示,整型信號量下的wait和signal操作可描述如下: 

  1. //整型信號量定義  
  2. int S;  
  3. //P操作  
  4. wait(S){  
  5. while(S<=0);  
  6. S--;  
  7.  
  8. //V操作  
  9. signal(S){  
  10. S++;  

​因為wait和signal操作是原子的,因此他們在執行的過程中是不可被中斷的。也就是說當一個進程在修改某個信號量時,沒有其他的進程可以同時對該信號量進行修改。

​需要注意的是,整型信號量的wait操作,只要是信號量S<=0,就會不斷的測試,讓進程處于一種“忙等”的狀態,沒有遵循讓權等待的原則。還有就是,把信號量的初值置為1,表示只允許一個進程訪問臨界資源,此時的信號量就可以轉換為互斥信號量,用于完成進程的互斥(對所有的信號量機制都是一樣)。

4.2 記錄型型號量

​為了解決整型信號量存在的忙等問題,應當采取讓權等待原則。但是又會出現一個新的問題,如果多個進程并發請求訪問臨界資源,除了第一個搶到了信號量外,其余的進程都應該釋放處理機,但是這些等待的進程要如何保存呢?為此,除了wait操作需要遵循讓權等待原則,還需在信號量中增加一個進程的鏈表指針list,用與鏈接上面描述的多個等待訪問臨界資源的進程。也因為記錄了等待的進程,這種信號量集之被稱為記錄型信號量。

​記錄型信號量具體的描述以及對應的wait和signal操作如下所示: 

  1. //記錄型信號量定義  
  2. typedef struct{  
  3. int value;  
  4. struct process_control_block *list;  
  5. }semaphore;  
  6. //P操作  
  7. wait(semaphore *S){  
  8. S->value--;  
  9. if(s->value < 0) {  
  10. block(S->list);  
  11.  
  12.  
  13. //V操作  
  14. signal(semaphore *S){  
  15. S->value++;  
  16. if(S->value <= 0){  
  17. wakeup(S->list);  
  18.  

​在記錄型型號量中,S->value的初值表示系統中某類資源的數目;對它每次wait操作,意味進程請求一個單位的該類資源,使得系統中可分配的該類資源數減少一個,因此描述為S->value–;當S.value<0時,表示在執行此次分配之前,系統中的該類資源已經全部分配完了,因此該訪問進程應調用block原語進行自我阻塞,放棄處理機并插入到等待進程的隊列S->list中。我們再來分析下signal操作,首先釋放一個單位資源(S->value++),然后判斷是否有進程在等待申請信號量,如果有的話,就應該調用wakeup原語從等待隊列(list所鏈接的進程隊列)中喚醒一個進程。

​通過上面的描述,我們來說一下在記錄型型號量中,value值所代表的意義:1.value>0,此時表示系統中還剩余的該類資源的數量;2.value=0,此時恰好處于一個平衡狀態,系統中的資源分配完了,同樣也沒有進程在等待資源,即list隊列中是沒有等待進程的;3.value<0,此時,value的絕對值表示有多少個進程在等待申請信號量,也即是list隊列的長度。并且P、V操作必須成對的出現,有一個P操作就必定有一個與之配對的V操作(當為互斥操作時,它們同處于同一進程當為同步操作時,則不在同一進程中出現)。

4.3 AND型信號量

​AND型號量正如其名,其基本思想是:將進程在整個運行過程中需要的所有資源,一次性的全部分配給進程,待進程使用完后再一起釋放。AND型號量可以滿足某些進程需要申請多個資源后才可以執行任務的場景,并且AND型信號量可以解決死鎖問題,比如哲學家進餐問題中,一次給哲學家分配左右兩支筷子,那么就不會有哲學家會因為吃不到空心粉而餓死了。

​AND型信號量使用的還是記錄型信號量的數據結構,下面是Swait操作和Ssignal操作(此處和下面的信號量集都用此符號): 

  1. //記錄型信號量定義  
  2. ...  
  3. //P操作  
  4. Swait(S1, S2, ..., Sn){  
  5. while(true){  
  6. if(S1>=1&&...&&Sn>=1){  
  7. for(i=1;i  
  8. break;  
  9. else {  
  10. 將進程插入到第一個無法滿足條件(即Si<1)的信號量對應的等待隊列中,并且將程序計數器放置到  
  11. Swait操作的開始處;  
  12.  
  13.  
  14.  
  15. //V操作  
  16. Ssignal(S1, S2, ..., Sn){  
  17. while(true){  
  18. for(i=1;i  
  19. Si++;  
  20. 將Si中的等待隊列中的所有進程全部移除,插入到就緒隊列中;  
  21.  
  22. break;  
  23.  

​需要注意的就是,因為一次申請多個資源,所以在申請的過程中,如果因為哪一類資源不足而阻塞(請求N多個資源時第一個發現不滿足的資源,即資源數<1),就要將進程插入到對應信號量的list中;與之對應的喚醒操作也有所不同,不再是喚醒阻塞隊列中的某一個進程,而是將等待隊列中的所有進程全部移除,插入到就緒隊列中,讓這些進程再次執行一次資源請求操作(這里因為是一次請求多個資源,后面可能依舊有資源無法滿足進程的需求)。

4.4 信號量集

​在前面講的信號量機制中,wait、signal操作僅能對信號量施以加1或者減1操作,當一次需要N個單位的資源時,便要執行N次的wait(S)操作,這顯然是低效的,并且會增大發生死鎖的概率(需要執行N次,在這N次執行的過程中可能會發生中斷,資源也可能會被別的進程搶占)。此外,在某些情況下,為了確保系統的安全性,當所申請的資源數量低于某一個下限時,就不予分配(保證地主家里有余糧)。

​為了滿足上述的兩個需求,信號量機制又升級了,在AND型信號量的基礎上進行擴充,對進程所申請的所有資源,在一次P、V操作中完成申請或釋放。并且進程對每類信號量的測試值也不在是1,而是該資源的分配下限ti,也就是要求Si≥ti,否則不予分配。因此這里就不在給出具體的Swait和Ssignal的代碼了,而是給出函數聲明: 

  1. Swait(S1, t1, d1, ... , Sn, tn, dn);  
  2. Ssignal(S1, d1, ... , Sn, dn); 

​這里與記錄性型號量稍有不同的地方就是判斷每類資源是否滿足需求時,判斷的條件由Si>=1變為Si>=ti,并且分配資源由Si--變為Si=Si-ti;與之對應的Ssignal操作,不同的一點就是,一次可以歸還多個資源,相對應的資源釋放代碼由Si++變為Si=Si+ti。

​需要注意的是,因為AND型信號量和信號量集一次申請進程執行所需的全部資源,這樣的優點就是簡單、易行且安全,但是缺點也很明顯:1.資源被嚴重浪費,嚴重的惡化了資源的利用率;2.使進程經常會發生饑餓現象(因為個別資源被占用的概率很大,會導致進程因為申請不到所有資源遲遲得不到執行)。

5.管程機制

​雖然信號量機制是一種既方便、又有效的進程同步機制,但是每個訪問臨界資源的進程都需要自備同步操作wait(S)和signal(S)操作,這就使大量的同步操作分散在各個進程中,不利于大家去集中的思考、抽象,使得程序設計的時候難度非常大,容易產生各種各樣的程序設計錯誤。在這樣的情況下,便產生了一種新的進程同步工具----管程(Monitors)。值得一提的是,管程也是迪杰斯特拉提出的。

​hansen對管程的定義如下:一個管程定義了一個數據結構和能力為并發進程所執行(在該數據結構上)的一組操作,這組操作能同步進程和改變管程中的數據。

​由上述的定義可知,管程有四部分組成:1.管程的名稱;2.共享數據結構說明;3.對數據結構進行操作的一組過程;4.初始化語句。下面我們來看下管程的語法描述: 

  1. //管程的描述  
  2. Monitor monitor_name {//管程名  
  3. share variable declarations; //共享變量說明  
  4. cond cond_declarationas; //條件變量說明  
  5. public: //能被進程調用的過程  
  6. void P1(...){ //對數據結構操作過程  
  7. ...  
  8.  
  9. void P2(...){  
  10. ...  
  11.  
  12. ...  
  13. void(...){  
  14. ...  
  15.  
  16. ...  
  17.  
  18. initilization code; //初始化代碼  
  19.  

​通過上面的代碼描述,你是不是覺得很熟悉!實際上,管程中包含了面向對象的思想,它將共享資源、對共享資源的操作抽象成變量和方法,并與同步機制一同封裝在一個對象內部,隱藏了實現細節。但是你所不知道的是,在管程出現的時候,還沒有面向對象程序設計,是不是很意外。

​封裝于管程內部的數據結構僅能被管程內部的過程訪問(類似于Java中的私有變量),如果想在管程外部訪問管程內部的數據結構,就必須使用內部過程(管程內部的public修飾的方法,Java 類中的公共方法)。所有的進程想要訪問臨界資源,都只能通過管程間接的訪問,并且管程每次只允許一個進程進入管程,從而實現了進程互斥。

​有一點需要說明的是,管程為了實現更加復雜的進程同步方式,增加了一個條件變量。通常會根據進程被阻塞或者掛起的原因,設置不同的條件變量,每個條件變量保存一個鏈表指針,用與鏈接所有因為該條件變量而阻塞或掛起的所有進程,同時提供兩個P、V操作也可以表示為x.wait和x.signal,這兩個操作的含義如下:

  1. x.wait:正在調用管程的進程因x條件需要被阻塞或掛起,則調用x.wait將自己插入到x條件的等待隊列中,并釋放管程,直至x條件發生變化。
  2. x.signal:正在調用管程的進程因為x條件發生了變化(資源使用完,歸還),則調用x.signal,重新啟動一個因x條件而阻塞或掛起的進程,如果存在多個,則選擇其中的一個,如果沒有,繼續執行原進程,不產生任何喚醒操作。

​對于上面的操作,其實是有些問題的,我們設想一下,如果進程P1因x條件處于阻塞狀態,那么當進程P2執行了x.signal操作喚醒P1后,進程P1和P2此時同時處于管程中了,這是不被允許的,那么如何確定哪個執行哪個等待?這個問題也很簡單,可采用下面的兩種方式之一進行處理:

  1. P2等待,直至P1離開管程或者等待另一個條件;
  2. P1等待,直至P2離開管程或者等待另一個條件。

​采用哪種處理方式,也存在很多爭論。Hoare采用了第一種處理方式,而Hansen采用了兩者的折中,它規定管程中的所有過程執行的signal操作是過程體的最后一個操作,于是,進程P2執行完signal操作后立即退出管程,因此進程P1馬上被恢復執行。

​但是hansen的這種折中的辦法,規定死了釋放的時機,增加了程序設計的難度。因此現在的管程普遍采用Hoare的方式,也被稱為霍爾管程。霍爾管程相比于管程、漢森管程,他的一個更大的優勢是可以基于PV操作原語來實現,換一句話說就是,wait和signal可以是程序過程而不需要是原語實現(可以使用語言機制實現霍爾管程)。這個就很厲害了,霍爾管程可以基于操作系統的程序庫或者是高級程序設計語言,在基礎的P、V操作原語上實現wait和signal操作,而不用擴展操作系統的內核。

​管程的示意圖如下,從圖中我們可以看到,每個條件變量都有一個對應的等待隊列,除了等待調用管程的進程隊列外,還有一個緊急隊列(優先級高,由進程調用signal操作后插入),對于具體的操作,我們可以結合霍爾管程中條件變量中的wait、signal操作來講。

​下面是霍爾管程的條件變量上的wait操作和signal操作的描述: 

  1. //霍爾管程使用的信號量定義  
  2. //semaphore為本文之前定義的記錄型信號量  
  3. typedef struct{  
  4. semaphore mutex; //用與管程調用的互斥信號量  
  5. semaphore next; //發出signal的進程掛起自己的信號量,信號量中記錄著等待調用管程的進程  
  6. int next_count; //在next上等待的進程數  
  7. }interf;  
  8. //霍爾管程中的條件變量  
  9. typedef struct{  
  10. semaphore x_sem; //與資源相關的信號量  
  11. int x_count; //在x_sem上等待的進程數  
  12. }cond;  
  13. //條件變量對應的wait操作  
  14. wait(cond declar, interf IM){  
  15. declar->x_count++; //在條件變量declar上等待的進程數量加1  
  16. if(IM->next_count > 0){ //判斷是否有進程在高優先級隊列中  
  17. V(IM->next); //喚醒因調用signal操作的進程  
  18. else {  
  19. V(IM->mutex); //沒有的話,喚醒一個等待進入管程的進程  
  20.  
  21. P(declar->x_sem); //釋放資源后,立即把自己掛起  
  22. declar->xcount--; //恢復執行后,重新開始執行,退出管程,條件變量declar等待的進程數量減1  
  23.  
  24. //條件變量對應的signal操作  
  25. signal(cond declar, interf IM){  
  26. if(declar->x_count > 0){ //判斷是否有等待條件變量的進程  
  27. IM->next_count++; //掛起自己后,因為調用signal掛起自己的進程數量加1  
  28. V(declar->x_sem); //喚醒一個等待條件變量的進程  
  29. P(IM->next); //釋放資源后,立即把自己掛起,進入高優先級隊列  
  30. IM->next_count--; //恢復執行后,等待調用的管程的進程數量減1  
  31.  

​我們看上面的代碼,此時的wait操作和signal操作與P、V原語是有區別的,wait和signal是在P、V的基礎上實現的。首先我們來看下wait操作,喚醒進程(高優先級隊列或者是等待調用管程的隊列)后,立即將自己掛起,并將自己插入到對應的條件變量的等待隊列中(上圖中左上方的隊列),當被喚醒再次執行時,將對應的等待數量減1。我們在來看下signal操作,首先判斷是否有等待條件變量的進程,如果沒有的話,就可以什么都不用執行;如果有進程在條件變量的等待隊列中,則從隊列中喚醒一個,并掛起自己,插入到緊急隊列中。

霍爾管程中的wait、signal操作比較抽象,可以結合圖片查看,可以幫助理解。

6.總結

​本文主要講了OS中為了解決進程同步問題才采取的措施,進程同步機制也是經過逐步的發展,慢慢的變得完善,可以滿足復雜的并發程序設計,本文的內容主要是偏理論,也結合了代碼來講解各個操作,能幫助大家理解。通過本文的學習,希望可以讓你在并發程序設計上能獲得理論的依據,因為我們做的更多的應該是多線程編程,如果你接觸過并發編程,我覺得本文里的許多內容能引起你的共鳴。

 

 

 

責任編輯:龐桂玉 來源: Csdn博客
相關推薦

2015-08-19 10:06:21

2012-09-12 09:40:36

云服務GIS技術彈性云計算

2011-12-16 11:11:24

戴爾

2010-06-14 23:32:04

綜合布線機場西蒙

2013-12-09 16:16:29

初志科技數據動車

2012-06-25 16:57:07

2014-07-01 10:07:56

2015-04-30 15:43:10

eLTE第53屆世乒賽華為

2025-02-11 08:23:41

2012-05-21 09:38:43

2012-11-13 18:24:03

LinOTPApache2一次性密碼

2011-01-04 15:37:44

2019-12-12 09:45:49

Docker容器漏洞攻擊

2013-02-01 16:48:16

2016-03-16 11:08:19

Zenlayer

2014-05-22 10:29:11

eLTE無線華為

2015-12-16 17:54:33

E店寶

2012-11-19 20:22:40

2012-02-13 10:46:37

TEMTivoliIBM
點贊
收藏

51CTO技術棧公眾號

538视频在线| 无码人妻久久一区二区三区 | 999久久久精品国产| 欧美日韩aaaaa| 中文字幕日韩精品无码内射| 亚洲男女视频在线观看| 久久婷婷亚洲| 色综合视频一区中文字幕| 无遮挡aaaaa大片免费看| 国产一区精品福利| 香蕉av福利精品导航| 日韩欧美亚洲精品| 精品国产乱码一区二区三| 亚洲制服少妇| 欧美日韩999| 久久久久亚洲av无码a片| 日本久久伊人| 精品视频一区二区不卡| 日韩国产一级片| 亚洲精品承认| 成人久久18免费网站麻豆 | caoporn国产| 综合天堂av久久久久久久| 亚洲女在线观看| 又黄又爽又色的视频| 成人日韩av| 疯狂做受xxxx欧美肥白少妇| 肉大捧一出免费观看网站在线播放| 性xxxxbbbb| 国产精品一二三区| 国产主播在线一区| 无码免费一区二区三区| 亚洲精品日本| 久久99久久99精品免观看粉嫩| 国产综合精品在线| 清纯唯美亚洲经典中文字幕| 日韩免费看网站| 中文字幕22页| 国产成人精品一区二区三区视频| 亚洲午夜久久久久久久久久久 | 亚洲黄色小说在线观看| 日韩毛片免费视频一级特黄| 91国在线观看| 成年人在线看片| 黄色在线观看www| 亚洲亚洲精品在线观看| 嫩草影院中文字幕| 在线欧美三级| 亚洲精品国产精品乱码不99| 中文字幕一区二区三区在线乱码 | 久久久久久久久一区二区| 法国空姐电影在线观看| 天堂一区二区三区四区| 亚洲第一在线视频| 2018国产精品| 国产日韩三级| 亚洲成人精品久久| 黄色免费视频网站| 女仆av观看一区| 亚洲精品国产精品国自产在线| 国产乱淫av片| 精品国产一区二区三区成人影院| 精品国产亚洲在线| 国产十八熟妇av成人一区| 精品久久对白| 亚洲欧洲偷拍精品| 69视频在线观看免费| 精品视频免费| 日韩有码在线播放| www.99re7| 激情视频一区二区三区| 午夜剧场成人观在线视频免费观看 | www.成人在线视频| 欧美日本一区二区| 亚洲欧美一区二区三区不卡| 久久久久九九精品影院| 精品久久久久久综合日本欧美| 老熟女高潮一区二区三区| 久久久久久毛片免费看 | 欧美日韩中文字幕日韩欧美| 免费观看精品视频| 免费在线观看一区| 欧美一区二区三区爱爱| 欧美夫妇交换xxx| 狠狠操综合网| 久久视频在线视频| 日韩av电影网| 美国一区二区三区在线播放 | 色综合视频网站| 国产精品自拍99| 日韩高清在线一区| 91精品久久久久久久久久久久久| www日本在线| 久久综合九色欧美综合狠狠| 亚洲国产激情一区二区三区| 影音先锋男人资源在线| 日韩欧美国产激情| 黄色片免费网址| 久久97久久97精品免视看秋霞| 亚洲视频电影图片偷拍一区| 欧美成人综合色| 久久美女性网| 97se亚洲综合| 超碰在线影院| 亚洲1区2区3区视频| 男女污污的视频| 2023国产精华国产精品| 在线观看亚洲区| 欧洲猛交xxxx乱大交3| 国产视频一区免费看| 成人欧美一区二区三区在线 | 国产亚洲精品美女久久久| 性生交大片免费全黄| 亚洲黄色成人| 亚洲一区亚洲二区亚洲三区| 国产裸舞福利在线视频合集| 亚洲在线视频一区| 色www免费视频| 亚洲人挤奶视频| 欧美激情综合亚洲一二区 | 日韩精品一区第一页| 97超级碰碰| 日本在线天堂| 在线观看免费成人| 风间由美一二三区av片| 国一区二区在线观看| 国产免费一区二区三区在线观看 | 最新欧美电影| 亚洲激情免费观看| 九九视频免费看| 久久91精品久久久久久秒播| 日韩中文字幕一区| 国产精品av一区二区三区 | 最新中文字幕日本| 在线看片不卡| 成人欧美一区二区三区黑人孕妇| www视频在线观看免费| 欧美日韩精品在线播放| 稀缺小u女呦精品呦| 五月婷婷六月综合| 国产日韩av高清| www.成人.com| 色综合久久久网| 短视频在线观看| 激情偷拍久久| 精品国产综合| 偷拍自拍在线看| 亚洲精品美女在线| 日本污视频在线观看| 成人午夜视频福利| 国产中文字幕乱人伦在线观看| 欧美经典一区| 欧美激情一二区| 亚洲黄色精品视频| 亚洲va欧美va天堂v国产综合| 欧美图片自拍偷拍| 国内精品美女在线观看| 国产精品久久久久久久久久直播| 影音先锋男人资源在线| 亚洲成人av在线播放| 激情小说中文字幕| 国产成人亚洲综合a∨婷婷图片| 男人草女人视频| 岛国精品一区| 55夜色66夜色国产精品视频| 激情小视频在线观看| 欧美在线观看一区| 国内毛片毛片毛片毛片毛片| 经典一区二区三区| 老司机午夜免费福利视频| 一区二区三区亚洲变态调教大结局 | 欧美日韩一区自拍| 精品久久久三级| 国产精品扒开腿做爽爽爽视频软件| 国产一区二区免费| 国产又粗又黄视频| 亚洲一区二区精品视频| 国产夫妻性爱视频| 久久www免费人成看片高清| 日韩video| 国产精品1luya在线播放| 日本久久久久久久| 蜜桃视频网站在线观看| 亚洲精品一区二区三区在线观看| 久久久久久久黄色片| 国产日韩成人精品| 国产成人强伦免费视频网站| 亚洲人体偷拍| 亚洲欧美日本国产有色 | 久久久久91| 正在播放国产精品| 欧美美女啪啪| 成人黄色片在线| 色在线视频观看| 色七七影院综合| 免费国产精品视频| 欧美性感一类影片在线播放| 欧美黄色免费在线观看| 久久久久国产成人精品亚洲午夜| www.久久久久久久久久久| 亚洲二区在线| 一本色道久久综合亚洲二区三区| 97人人澡人人爽91综合色| 国产精品爱久久久久久久| 日本高清在线观看| 中文字幕av一区| 无码h黄肉3d动漫在线观看| 欧美日韩一区二区三区在线| 日韩av黄色片| 日韩理论片在线| 欧洲女同同性吃奶| 成人性生交大片免费看视频在线 | 久久一级黄色片| 中文字幕欧美三区| 中文乱码人妻一区二区三区视频| 久久 天天综合| 日韩手机在线观看视频| 在线欧美不卡| 2021国产视频| 国产 欧美 在线| 蜜桃一区二区三区在线| 久久免费视频3| 欧美激情综合色综合啪啪| 亚洲国产日韩综合一区| 亚瑟一区二区三区四区| 成人av影视在线| 日本午夜精品久久久久| 国产成一区二区| 在线女人免费视频| 97av在线视频| 电影k8一区二区三区久久| 不卡毛片在线看| 免费在线你懂的| 最新的欧美黄色| 成人在线播放视频| 亚洲女人天堂成人av在线| 天堂资源中文在线| 亚洲电影免费观看| 欧美熟妇交换久久久久久分类| 日韩一区二区三区在线观看| 国产免费高清视频| 欧美日韩www| 国产乱淫av片免费| 91精品国产一区二区三区 | 日本aⅴ亚洲精品中文乱码| 亚洲色成人一区二区三区小说| 国产欧美不卡| 成人毛片视频网站| 国产日韩精品视频一区二区三区 | 精品国产乱码久久久久久蜜臀 | 国产精品自拍一区| www.成年人| 国产精品99精品久久免费| 精品人妻一区二区三区免费| 国产成人精品www牛牛影视| 日本女人性视频| 丁香激情综合国产| 精品一区二区视频在线观看| 99国产精品国产精品毛片| 亚洲制服丝袜在线播放| 国产亚洲一区二区在线观看| 人与嘼交av免费| 中文在线一区二区| 加勒比婷婷色综合久久| 亚洲高清不卡在线| 国产精品视频123| 色琪琪一区二区三区亚洲区| 国产精品国产精品国产| 欧美日韩国产免费一区二区| 91欧美日韩麻豆精品| 日韩欧美电影一区| 天天干天天干天天干| 亚洲全黄一级网站| 亚洲成人三级| 欧美精品videossex性护士| 激情视频网站在线播放色| 国产精品成人av性教育| 91嫩草国产线观看亚洲一区二区| 国产成人成网站在线播放青青| 色爱综合av| 亚洲一区二区在线看| 66视频精品| 国产视频九色蝌蚪| 日本v片在线高清不卡在线观看| 香蕉视频xxxx| 久久午夜电影网| 欧美日韩色视频| 五月婷婷色综合| 在线亚洲欧美日韩| 精品精品欲导航| 国产爆初菊在线观看免费视频网站| 日韩视频永久免费观看| 电影在线观看一区| 国产欧美久久久久久| 成人福利一区| 亚洲日本精品国产第一区| 亚洲大胆av| 天美一区二区三区| 久久久三级国产网站| 强行糟蹋人妻hd中文| 91国偷自产一区二区使用方法| 精品人妻伦一区二区三区久久| 日韩精品视频在线观看免费| 麻豆网站在线观看| 日韩av电影在线免费播放| 日韩成人精品| 天天综合狠狠精品| 亚洲精品影视| 亚洲综合20p| 国产日韩成人精品| 日韩 欧美 中文| 欧美一区二区三区小说| 国产视频第一区| 91精品国产91久久久久久吃药| 综合久久av| 日韩三级电影网站| 中文高清一区| 91蝌蚪视频在线| 国产精品网站在线观看| 精品美女久久久久| 日韩精品一区二区三区三区免费| 91精彩视频在线播放| 日韩av免费看网站| 久久夜色电影| 91.com在线| 国产精品综合av一区二区国产馆| 99热6这里只有精品| 日本韩国欧美一区二区三区| 亚洲人成色777777精品音频| 欧美黑人xxx| 麻豆一二三区精品蜜桃| 一区二区三区四区| 蜜臀av性久久久久av蜜臀妖精| 少妇真人直播免费视频| 五月天久久比比资源色| 亚洲国产精品二区| 另类专区欧美制服同性| 91精品网站在线观看| 伊人天天久久大香线蕉av色| 美女视频黄 久久| 内射毛片内射国产夫妻| 91国产免费观看| 丁香婷婷在线观看| 国产精品第8页| 日韩成人免费| 性生活免费在线观看| 国产精品久久久久天堂| 一级久久久久久久| 久久精品国产91精品亚洲| 97久久中文字幕| 激情六月天婷婷| 成人一级片在线观看| 亚洲视频免费播放| 精品五月天久久| 亚洲成人短视频| 日韩在线电影一区| 激情久久五月天| 欧美三级小视频| 亚洲成人亚洲激情| 亚洲精品成人图区| 少妇免费毛片久久久久久久久| 免费成人在线影院| 精品自拍偷拍视频| 精品成人a区在线观看| 欧美日韩国产观看视频| 欧美在线视频一区二区三区| 免费观看日韩av| 18岁成人毛片| 亚洲激情 国产| jizzjizz少妇亚洲水多| 人人妻人人澡人人爽精品欧美一区| 国产精一区二区三区| 精品在线视频免费| 日韩av在线电影网| 国产成人精选| 女人床在线观看| 91原创在线视频| 在线观看一二三区| 久久免费精品视频| 欧美综合在线视频观看| 国产不卡的av| 黑人巨大精品欧美一区二区免费| 国产福利小视频在线观看| 91在线中文字幕| 美女黄网久久| 一区二区视频免费看| 日韩激情视频在线| 亚洲成人精品综合在线| 无码粉嫩虎白一线天在线观看 | jizz一区二区三区| 极品日韩久久| 久久爱www久久做| 免费观看成人毛片| 久久久精品日本| 日韩欧美ww| 又黄又爽又色的视频| 色猫猫国产区一区二在线视频| 激情在线小视频| 欧美一区二区三区四区夜夜大片| 国产一区二区三区四区五区美女|