“ 消費者-生產者” 模型:
問題描述:
兩個共享固定大小的線程——即所謂的“生產者”和“消費者”——在實際運行時會發生的問題。生產者的主要作用是生成一定量的數據放到緩沖區中,然后重復此過程。與此同時,消費者也在緩沖區消耗這些數據。該問題的關鍵就是要保證生產者不會在緩沖區滿時加入數據,消費者也不會在緩沖區中空時消耗數據。
涉及操作:
PV操作:
P操作: 申請一個特定的資源,資源數量先減1,如果現在資源數量>=0, 說明已經申請成功了,則可進入臨界區;否則如果現在資源<0,則被阻塞,進入阻塞隊列,后續的其他進程進行P操作則會使該資源數量繼續減1,并進入阻塞隊列。這里的資源數量也就是信號量。
V操作: 釋放一個特定的資源,資源數量先加1,也就是信號量加1,如果現在的資源<=0,則說明阻塞隊列存在進程正在等待資源,則將阻塞隊列的一個進程喚醒;否則如果現在資源>0, 則說明沒有進程等待。
消費者-生產者
一開始自己并不理解為什么要這么寫消費者-生產者模型,以下記錄自己的思考過程:
- 首先,有一個臨界資源也就是放置生產物品的地方,就叫s吧,每次只能一個生產者或消費者去取或者放,不然就亂套了。
semphore s=1; //信號量,表示共享區,1表示可用,0表示不可用
void producer() { //生產者
while(true){
produce();//生產物品過程,不能放在申請p操作以后,不然可能要占著共享區進行生產,會耗費很長時間
p(s); //申請
放置資源操作;
v(s); //釋放
}
}
void consumer() { //消費者
while(true){
p(s);//申請
取出資源操作;
v(s);//釋放
consume()
}
}
-
想想如果很多個生產者放置資源,而沒有消費者取出資源,那共享區不就滿了嗎?按照上面的程序好像無法限制共享區的位置數量。
這好辦,把s設置為5;表示有5個資源位置,那生產者一進來就能進行P申請操作,直到s為0表示沒有位置了,好像達到目的了,但是,消費者一進來也同樣看到s不為0,同樣可以申請位置去取出資源,但是事實上s表示的是位置數量而不是有多少資源數量,消費者占著位置,可是該位置上卻沒有資源。
此時可以用兩個信號量full和empty,分別表示有資源的位置數量和無資源的位置數量:
semphore full = 0;
semphore empty = 5;
int in = 0;//表示放資源的位置
int out = 0;//表示取資源的位置
int s[];
void producer() { //生產者
while(true){
produce();
p(empty);//申請一個空的位置
s[in] =1;//放置資源
in=(in+1)%5;
v(full);//釋放增加一個滿的位置
}
}
void consumer() { //消費者
while(true){
p(full);//申請一個滿的位置
s[out] =0;//取出資源
out = (out+1)%5;
v(empty);//釋放增加一個空的位置
consume();
}
}
-
但是這樣有個問題:比如當多個生產者同時放置,那么可能會同時執行
s[in] =1;//放置資源
in=(in+1)%5;
可能會放在同樣的位置,因為并沒有要求只能一個生產者進入共享區放資源,所以我們需要多一個互斥量mutex,表示共享區:
semphore full = 0;
semphore empty = 5;
semphore mutex = 1;
int in = 0;//表示放資源的位置
int out = 0;//表示取資源的位置
int s[];
void producer() { //生產者
while(true){
produce();
p(empty);//申請一個空的位置
p(mutex);//申請進入共享區
s[in] =1;//放置資源
in=(in+1)%5;
v(mutex);
v(full);//釋放增加一個滿的位置
}
}
void consumer() { //消費者
while(true){
p(full);//申請一個滿的位置
p(mutex);
s[out] =0;//取出資源
out = (out+1)%5;
v(mutex);
v(empty);//釋放增加一個空的位置
consume();
}
}