1.理解生產者和消費者問題
沒有引入信號量時的生產者和消費者進程,什么情況下會出現結果不唯一?什么情況下會出現永遠等待?
用信號解決生產者和消費者的同步與互斥,要求能自己寫出來。
答:sleep()和wakeup()是操作系統基本內核函數,他們被封裝在函數庫中供應用程序使用,執行sleep()時,讓調用進程進入等資源隊列,當資源可用時從相應隊列釋放等資源的進程。
結果不唯一:當進程之間共享變量counter,對counter的訪問未加限制,生產者進程和消費者進程對counter的交替操作會使其結果不唯一,例如counter的當前值為8,如果生產者生產一件產品並投入緩沖區,擬執行counter加1操縱,同時消費者獲取一個產品消費,擬執行counter減1操作,假如兩者交替執行加1或減1操作,取決於其執行速度,counter的值可能是9,也可能是7,但是其正確值應該是8.
出現永遠等待:假定消費者讀取counter值時發現它為0,此時調度程序暫停消費者進程,讓生產者進程運行,生產者加入一個產品,將counter的值加1,他想當然的推想由於counter值剛才為0,所以此時消費者一定是在睡眠,於是生產者調用wakeup()函數來喚醒消費者,遺憾的是,消費者尚未睡眠時喚醒信號丟失,當消費者下次運行時,因已測到counter的值為0,於是去睡眠,這樣生產者遲早會填滿緩沖區然后去睡眠,這樣就造成了所有進程都永遠處於睡眠狀態。
PV操作:
item B[k];
semaphore empty;empty=k;
semaphore full;full=0;
semaphore mutex;mutex=1;
int in=0;
int out=0;
cobegin
process producer_i)(){
while(ture){
produce();
P(empty);
P(mutex);
apppend to B[in];
in=(in+1)%k;
V(mutex);
V(full);
}
process consumer_j(){
while(ture){
P(full);
P(Mutex);
take from B[out];
out=(out+1)%k;
V(muter);
V(empty);
consume();
}
}
}
2.哲學家吃面問題
semaphore fore[5];
for (int i=0;i<5;i++)
{
fork[i]=1;
}
cobegin
process philosopher_i(){
while(ture){
think();
P(fork[i]);
P(fork[(i+1)%5]);
eat();
V(fork[i]);
V(fork[(i+1)%5]);
}
}
coend
分析:顯然,最多兩個哲學家同時吃面,假如每個哲學家都拿起一只筷子,就會永久等待(死鎖),下面介紹一種方法。
typedef int Semaphore; //定義信號量Semaphore類型是整型的別名 const int N = 5; //定義哲學家的數目,該數目可以根據需要修改 const LEFT (i-1)%N; //哲學家i的左鄰 const RIGHT (i+1)%N; //哲學家i的右鄰 enum status{Thinking,Hungry,Eating};//哲學家所處的三種狀態的常量枚舉 Semaphore mutex = 1; //定義一個互斥信號量,實現對臨界區的互斥 semaphore s[N] = {0}; //每個哲學家對應的信號量,初值為0 int state[N]; //每個哲學家的狀態數組
void TakeChopstick(int i) //第i個哲學家試圖拿筷子 { P(mutex); //進入訪問共享變量state[i]的臨界區前對mutex的P操作 state[i]=Hungry; //設置狀態為飢餓 test(i); //測試能不能取筷子 V(mutex); //起開臨界區 P(s[i]); //如果沒有筷子,進程阻塞 }
void PutChopstick(int i) //哲學家i放下筷子 { P(mutex); //訪問臨界區的互斥信號量 State[i]=Thinking; //吃完了,放下筷子進入思考狀態 test(LEST); //喚醒左邊哲學家拿筷子 test(RIGHT); //喚醒右邊哲學家拿筷子 V(mutex); //離開臨界區 }
void test(int i) { if(state[i]==Hungry && state[LEFT] != Eating &&state[RIGHT] !=Eating) { State[i]=Eating; V(s[i]); //喚醒哲學家進程,喚醒當前被阻塞的進程 } }
process Phliospher(int i) { while(1) { 思考; TakeChopstick(i); 吃面條; PutChopstick(i); } }
3.讀寫文件問題
單純使用信號量不能解決此此問題,必須引入計數器readcount對讀進程計數,mutex是用於對計數器readcount操作的互斥信號量,writerblock表示是否允許寫的信號量。
int readcount=0;
semaphore writeblock,mutex;
writeblock=1;mutex=1;
cobegin
process reader_i(){ process writer_j(){
P(mutex); P(writeblock);
readcount++; V(writeblock);
if(readcount==1) }
P(writeblock);
V(mutex);
P(mutex);
readcount--;
if(readcount==0)
V(writeblock);
V(mutex);
}
coend
4.理發師問題
int waiting =0;
int CHAIRS=N;
semaphore customers,barbers,mutex;
customers=0;barber=0;mutex=1;
cobegin
process barbers(){
while(ture){
P(customers);
P(mutex);
waiting--;
V(barber);
V(mutex);
cutair();
}
}
process customer_i(){
P(mutex);
If(waiting<CHAIRS){
waiting++;
V(customers);
V(mutex);
P(barbers);
get_haircut();
}
else
V(mutex);
}
coend
第一隊音樂愛好者要競爭“待出售的音樂磁帶和電池”,而且在初始狀態下,系統並無“待出售的音樂磁帶和電池”,故可為該種資源設置一初值為0的信號量buy1,同樣,需設置初值為0的buy2、buy3分別對應“待出售的隨聲聽和電池”、"待出售的隨聲聽和音樂磁帶"。另外,為了同步買者的付費動作和給貨動作,還需設置信號量payment和goods,以保證買者在付費后才能得到所需商品,信號量music overi用來同步音樂愛好者聽樂曲和酒吧老板的下一次出售行為,具體如下:
semaphore buy1=buy2=buy3=0;
semaphore payment=0;
semaphore goods=0;
swmaphore music_over=0;
cobegin{
process boss(){//酒吧老板
while(ture){
拿出任意兩種物品出售;
if(出售的是音樂磁帶和電池) V (buy1);
else if(出售的是隨聲聽和電池) V(buy2);
else if(出售的是隨聲聽和音樂磁帶) V(buy3);
P(payment);//等待支付
V(goods);//給貨
P(music_over);//等待樂曲結束
}
}
process fan1(){//第1隊音樂愛好者
while(ture){//因為一個進程代表一隊,而不是一個愛好者,所以這里是//while(ture)
P(buy1);//等有音樂磁帶和電池出售
V(payment);//付費
P(goods);//取貨
欣賞一曲樂曲;
V(music_over);//通知老板樂曲結束
}
}
process fan2(){//第二隊音樂愛好者
while(ture){
P(buy2); //等有隨聲聽和電池出售
V(payment);//付費
P(goods);//取貨
欣賞一曲樂曲;
V(music_over);//通知老板樂曲結束
}
}
process fan3(){//第三隊音樂愛好者
while(ture){
P(buy3); //等有隨聲聽和音樂磁帶出售
V(payment);//付費
P(goods);//取貨
欣賞一曲樂曲;
V(music_over);//通知老板樂曲結束
}
}
coend
6.某銀行有人民幣儲蓄業務,由n個儲蓄員負責。每個顧客進入銀行后先取一個號,並且等着叫號。當一個儲蓄人員空閑下來,就叫下一個號。請用P,V操作正確編寫儲蓄人員和顧客進程的程序。
var customer_counter,mutex:semaphore;
customer_counter:=0;
mutex:=1;
cobegin
process customer
begin
L1:take a number;
P(mutex0);
進入隊列;
V(mutex);
V(customer_count);
go to L1;
end
Process serversi(i=1,2,3...)
begin
P(cunstom_count);
P(mutex);
從隊列區號;
V(mutex);
為該號客人服務;
end;
coend;
8.九、在一個盒子里,混裝了相等數量的黑棋子和白棋子,現要用自動分揀系統把黑棋子和白棋子分開,該系統由兩個並發執行的進程P1和P2組成,其中進程P1專門揀黑子,進程P2專門揀白子。規定兩個進程輪流揀子且每個進程每次只揀一個子。當一個進程在揀子時不允許另一個進程去揀子,並設P1先揀。請用P,V操作管理這兩個並發進程,使其能正確實現上述功能
var S1,S2:semaphore;
S1:=1;S2:=0;
cobegin
{
process P1
begin
repeat
P(S1);
揀白子
V(S2);
until false;
end
process P2
begin
repeat
P(S2);
揀黑子
V(S1);
until false;
end
}
coend.