本文爲博主原創文章,未經博主容許不得轉載 http://www.cnblogs.com/kiplove/p/6745335.htmlhtml
涉及進程同步的一些概念:算法
互斥與同步:數組
臨界資源(臨界區):指一次只能容許一個進程使用的共享資源稱爲臨界資源;緩存
同步:指爲完成某種任務而創建的兩個和多個進程,這些進程在合做的過程當中須要協調工做次序進行有序的訪問而出現等待所產生的制約關係。安全
互斥:指兩個或多個進程訪問臨界資源時只能一個進程訪問,其餘進程等待的一種相互制約的關係。併發
信號量與互斥量:spa
信號量:自己是一個計數器,使用P,V兩個操做來實現計數的減與加,當計數不大於0時,則進程進入睡眠狀態,它用於爲多個進程提供共享數據對象的訪問。code
互斥量:若是信號量只存在兩個狀態,那就不須要計數了,能夠簡化爲加鎖與解鎖兩個功能,這就是互斥量。htm
1、生產者與消費者問題對象
問題描述:一組生產者進程和一組消費者進程共享一塊初始爲空,大小肯定的緩衝區,只有當緩衝區爲滿時,生產者進程才能夠把信息放入緩衝區,不然就要等待;只有緩存區不爲空時,消費者進程才能從中取出消息,不然就要等待。緩衝區一次只能一個進程訪問(臨界資源)。
問題分析:生產者與消費者進程對緩衝區的訪問是互斥關係,而生產者與消費者自己又存在同步關係,即必須生成以後才能消費。於是對於緩衝區的訪問設置一個互斥量,再設置兩個信號量一個記錄空閒緩衝區單元,一個記錄滿緩衝區單元來實現生產者與消費者的同步。
問題解決:僞代碼實現
semaphore mutex=1; semaphore full=0; //滿緩衝區單元 semaphore empty=N; //空閒緩衝區單元 prodecer() { while(1) { P(empty); P(mutex); add_source++; V(mutex); V(full); } } consumer() { while(1) { P(full); P(mutex); add_source--; V(mutex); V(empty); } }
2、讀者與寫者問題
問題描述:有讀者與寫者兩個併發進程共享一個數據,兩個或以上的讀進程能夠訪問數據,可是一個寫者進程訪問數據與其餘進程都互斥。
問題分析:讀者與寫者是互斥關係,寫者與寫者是互斥關係,讀者與讀者是同步關係。於是須要一個互斥量實現讀與寫和寫與寫互斥,一個讀者的訪問計數和實現對計數的互斥。
問題解決:三種僞代碼實現
一、讀者優先
讀者優先,只要有讀者源源不斷,寫者就得不到資源。容易形成寫者飢餓。
1 //讀者優先 2 3 int count=0; 4 semaphore mutex=1; //讀者計數鎖 5 semaphore rw=1; //資源訪問鎖 6 7 writer() 8 { 9 while(1) 10 { 11 P(rw); 12 writing sth; 13 V(rw); 14 } 15 } 16 17 reader() 18 { 19 while(1) 20 { 21 P(mutex); 22 if(count==0) 23 P(rw); 24 count++; 25 V(mutex); 26 reading sth; 27 P(mutex); 28 count--; 29 if(count==0) 30 V(rw); 31 V(mutex); 32 } 33 }
二、讀寫公平
讀者與寫者公平搶佔資源,可是隻要以前已經排隊的讀者,就算寫者獲取的資源,也要等待全部等待的讀者進程結束。
1 //讀寫公平 2 int count=0; 3 semaphore mutex=1; //讀者計數鎖 4 semaphore rw=1; //資源訪問鎖 5 semaphore w=1; //讀寫公平搶佔鎖 6 writer() 7 { 8 while(1) 9 { 10 P(w); 11 P(rw); 12 writing sth; 13 V(rw); 14 V(w); 15 } 16 } 17 18 reader() 19 { 20 while(1) 21 { 22 P(w); 23 P(mutex); 24 if(count==0) 25 P(rw); 26 count++; 27 V(mutex); 28 V(w); 29 reading sth; 30 P(mutex); 31 count--; 32 if(count==0) 33 V(rw); 34 V(mutex); 35 } 36 }
三、寫者優先
寫者優先,只要寫者源源不斷,讀者就得不到資源,可是在這以前已經排隊的的讀者進程依然能夠優先得到資源,在這以後則等待全部寫者進程的結束。這種也易形成讀者飢餓。
1 //寫者優先 2 int write_count=0; //寫計數 3 int count=0; //讀計數 4 semaphore w_mutex=1; //讀計數時鎖 5 semaphore r_mutex=1; //寫計數時鎖 6 semaphore rw=1; //寫優先鎖 7 semaphore source=1; //資源訪問鎖 8 9 writer() 10 { 11 while(1) 12 { 13 P(w_mutux); 14 if(write_count==0) 15 P(rw); //得到則只要有寫進程進來就不釋放 16 write_count++; 17 V(w_mutux) 18 19 P(resouce); //寫時互斥必須加資源獨佔的鎖 20 writing sth; 21 V(resouce); 22 23 P(w_mutux); 24 write_count--; 25 if(write_count==0) 26 V(rw); 27 V(w_mutux); 28 } 29 } 30 31 reader() 32 { 33 while(1) 34 { 35 P(rw); //使用了當即釋放 36 P(r_mutex); 37 if(count==0) 38 P(resouce); 39 count++; 40 V(r_mutex); 41 V(rw); 42 43 reading sth; 44 45 P(r_mutex); 46 count--; 47 if(count==0) 48 V(resouce); 49 V(r_mutex); 50 } 51 }
3、哲學家就餐問題
問題描述:一張圓桌上坐着五名哲學家,每兩名哲學家之間的桌子擺一根筷子,哲學家只有同時拿起左右兩根筷子時才能夠用餐,用餐完了筷子放回原處。
問題分析:這裏五名哲學家就是五個進程,五根筷子是須要獲取的資源。能夠定義互斥數組用於表示五根筷子的互斥訪問,爲了防止哲學家個取一根筷子出現死鎖,須要添加必定的限制條件。一種方法是限制僅當哲學家左右筷子都可以用時,纔拿起筷子,這裏須要一個互斥量來限制獲取筷子不會出現競爭。
問題解決:一次僅能一個哲學家拿起筷子,效率比較低。
1 semaphore chopstick[5]={1,1,1,1,1}; 2 semaphore mutex=1; 3 pi() 4 { 5 while(1) 6 { 7 P(mutex); 8 P(chopstick[i]); 9 P(chopstick[(i+1)%5]); 10 V(mutex); 11 12 eating; 13 14 V(chopstick[i]); 15 V(chopstick[(i+1)%5]); 16 } 17 }
補充內容
死鎖:若是一個進程集合中的每一個進程都在等待只能由該進程集合中的其餘進程才能引起的事件,那麼該進程集合就是死鎖的。
死鎖的條件(四個同時知足):
(1)互斥:每一個資源要麼已經分配給一個進程,要麼就是可用的;
(2)佔有和等待:已經獲得的某個資源的進程請求新的資源;
(3)不可搶佔:已經分配的資源不能強制被搶佔,只能進程本身顯示的釋放;
(4)環路等待:存在一種進程資源的循環等待鏈。
死鎖的處理策略:
(1)死鎖預防:破壞死鎖的四個條件之一
破環互斥條件:容許資源共享
破環佔有和等待條件:採用預先靜態分配
不可搶佔:請求新資源得不到時,釋放已經保持佔有的資源,待之後從新申請
環路等待:採用順序資源分配法
(2)死鎖避免:死鎖避免事先預防策略,可是是採用資源動態分配的過程當中,防止系統進入不安全狀態,以免死鎖。
銀行家算法:可利用資源矢量Available,請求矢量Request
最大需求矩陣Max,分配矩陣Allocation,需求矩陣Need
經過Need=Max-Allocation得到每一個進程須要的各種資源數Need矩陣
通常每一個進程請求矢量應該小於等於Need的值
試探分配:Available=Avaliable-Request
Allocate相對應的項=Allocate相對應的項+Request
Need相對應的項=Need相對應的項-Request
安全性算法:檢查資源分配後,系統是否屬於安全狀態,若是安全才正式分配資源,不然做廢。通常經過安全性算法推算一個安全序列(核心)。
(3)死鎖檢測與解除:
檢測死鎖:利用死鎖原理化簡資源分配圖檢測死鎖的存在
死鎖解除:資源剝奪、撤銷進程、進程回退