1.生产者和消费者问题
这个问题一共有三个角色:生产者,消费者和缓冲池
对于这个问题,咱们分三个阶段来看
第一个问题,一个生产者,一个消费者和一个缓冲池怎么解决?
在解决问题之前先分析清楚需要干什么
- 进程
- 活动
- 分析关系
- 信号量
这是解决这类问题比较重要的四步
而关系又分为互斥,同步,资源
进程是两个,一个是生产者,一个是消费者
活动:生产和消费
关系:同步
接下来我们来写程序(伪代码):
写单词:buffer是缓冲的意思
semaphore empty=1,full=0;
producer(){
while(1){
produce an item nextp;//生产出产品
wait(empty);
buffer=nextp;//将产品存入缓冲区
signal(full);
}
}
consumer(){
while(1){
wait(full);
nextc=buffer;
signal(empty);
}
}//将产品从缓冲区里取出,并置为空
bingo!第一个问题解决了
咱们来进阶一下
现在有一个生产者,一个消费者和n个缓冲区,该如何解决呢?
只需要在原来的基础上进行修改
既然有n个缓冲区,那咱们就设一个大小为n的数组好了
还需要加什么呢?对,需要进行取余运算
semaphore empty=1,full=0;
int in=0,out=0;
int buffer[n];
producer(){
while(1){
produce an item nextp;
wait(empty);
buffer[in]=nextp;
in=(in+1)%n;
signal(full);
}
}
consumer(){
while(1){
wait(full);
nextc=buffer[out];
out=(out+1)%n;
signal(empty);
consume the item in nextc;
}
}
最后,我们来看有n个消费者,n个生产者,n个缓冲区的问题
semaphore empty=1,full=0,mutex=1;
int in=0,out=0;
int buffer[n];
producer(){
while(1){
produce an item nextp;
wait(empty);
wait(mutex);
buffer[in]=nextp;
in=(in+1)%n;
signal(full);
signal(mutex);
}
}
consumer(){
while(1){
wait(full);
wait(mutex);
nextc=buffer[out];
out=(out+1)%n;
signal(empty);
signal(mutex);
consume the item in nextc;
}
}
看完了读者-写者问题咱们再看一个补充的题目
有一座东西方向的独木桥;用P,V操作实现:
(1) 每次只允许一个人过桥;
(2) 当独木桥上有自东向西的行人时,同方向的行人可以同时过桥,从西向东的方向,只允许一个人单独过桥。
(3) 当独木桥上有行人时,同方向的行人可以同时过桥,相反方向的人必须等待。
这个问题就可以简化为读者写者问题
第一种情况只允许一个人过桥,可以看成进程之间是互斥的。就跟读者跟写者之间是互斥的一样,只不过是没有这个身份上的差异罢了。
上伪代码:
semaphore s=1;
man(){
while(1){
wait(s);
过桥;
signal(s);
}
}//就设一个信号量让他们互斥使用就行了
我们来看第二个问题:
这个就跟读者写者问题比较相似了,它分为从东向西和从西向东两个身份。
EastToWest(){
wait(S1);
if(EWcount==0){
wait(S2);//申请互斥使用权
}
EWcount++;
signal(S1);
过桥;
wait(S1);
EWcount--;
if(EWcount==0){
signal(S2);
}
signal(S1);
}
WestToEast(){
wait(S2);
过桥;
signal(S2);
}
跟读者写者问题大差不差。
来看第三个进阶点的问题,就相当于是可以有多个读者同时去读,多个写者同时去写,但是读者和写者之间是互斥的关系。
需要修改的是进程WestToEast();
EastToWest(){
wait(S1);
if(EWcount==0){
wait(S2);//申请互斥使用权
}
EWcount++;
signal(S1);
过桥;
wait(S1);
EWcount--;
if(EWcount==0){
signal(S2);
}
signal(S1);
}
WestToEast(){
wait(S2);
if(WEcount==0){
wait(S1);//申请互斥使用权
}
WEcount++;
signal(S2);
过桥;
wait(S2);
EWcount--;
if(EWcount==0){
signal(S1);
}
signal(S2);
}
印象中和老师写的有点不太一样,她好像还设了一个S3,忘了怎么弄的了。。。
信号量的应用
习题一
在一个盒子里,混装了数量相等的黑白围棋子。
现在用自动分拣系统把黑子、白子分开,设分拣系统有两个进程P1和P2,
其中P1拣白子,P2拣黑子。规定当一个进程拣了一子后,必须让另一个进程去拣。
用信号量和PV操作协调两进程的活动。
Struct semaphore S1, S2;
S1.value=1; S2.value=0;
cobegin
process P1(){
while(true){
P(S1);
拣白子
V(S1);
}
}
coend
process P2(){
while(true){
P(S2);
拣黑子
V(S2);
}
}
习题二
某控制系统中,数据采集进程负责把采集到的数据放到一缓冲区中,分析进程负责把数据从缓冲区中取出进行分析,试用信号量实现两者之间的同步
int Se=1;
int Sf=0;
mian(){
cobegin;
get();
compute();
coend
}
get(){
while(采集工作未完成){
采集一个数据;
P(Se);
将数据送入缓冲区;
V(Sf);
}
}
compute(){
while(计算工作未完成){
P(Sf);
从缓冲区中取出数据;
V(Se);
进行数据计算;
}
}
习题四
一家四人父、母、儿子、女儿围桌而坐;桌上有一个水果盘;
当水果盘空时,父亲可以放香蕉或者母亲可以放苹果,但盘中已有水果时,就不能放,父母等待。
当盘中有香蕉时,女儿可吃香蕉,否则,女儿等待;
当盘中有苹果时,儿子可吃,否则,儿子等待。
int S=1;
int So=0;
int Sa=0;
main(){
cobegin;
father();
son();
daughter();
coend;
}
father(){
while(1){
P(S);
将水果放入盘中;
if(放入的是橘子){
V(So);
}else{
V(Sa);
}
}
}
son(){
while(1){
P(So);
从盘中取出橘子;
V(S);
吃橘子;
}
}
daughter(){
while(1){
P(S);
从盘中取出苹果;
V(S);
吃苹果;
}
}
习题五
在公共汽车上,司机和售票员的活动分别是:
司机的活动: 启动车辆
正常运行
到站停车
售票员的活动: 关车门
售票
开车门
在汽车不断的到站,停车,行驶过程中,司机和售票员
的活动有什么同步关系?用信号量和P,V操作实现.
习题六
有一个超市,最多可容纳N个人进入购物,当N个顾客满员时,后到的顾客在超市外等待;
超市中只有一个收银员。
可以把顾客和收银员看作两类进程,两类进程间存在同步关系。
写出用P;V操作实现的两类进程的算法