一、生产者—消费者问题
1、原型
问题描述:
一组生产者进程和一组消费者进程共享一个初始为空、大小为 n 的缓冲区,只有缓冲区没满时,生产者才把消息放入缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中读取消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或一个消费者从中取出消息。
分析:
1)关系分析:
生产者和消费者对缓冲区的访问属于互斥关系,而针对“消息”则生产者和消费者属于协作关系,只有生产者生产了消息,消费者才能使用消息,因此又是同步关系。
2)思路整理:
两组进程存在互斥和同步关系,也就是要解决互斥和同步PV的操作的位置。
3)信号量设置:
2、改进版
问题描述:
桌子上有一个盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专吃盘子中的橘子,女儿专等吃盘子中的苹果。只有盘子为空时,爸爸或妈妈才可以向盘子中放一个水果;仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出。
分析:
1)关系分析:
爸爸和妈妈是互斥关系,爸爸和女儿、妈妈和儿子是同步关系,而且这两对进程必须连起来,儿子和女儿之间没有互斥和同步关系,因为他们是选择条件执行。
2)思路整理
这里一共由4个进程,可抽象为两个生产者和两个消费者被连接到大小为1的缓冲区上。
3)信号设置
信号量 plat
e 表示互斥信号量
,用于确定是否可以往盘子中放水果
,初值为 1 表示允许放入一个;信号量 apple 表示盘中是否还有苹果,初值为 0表示没有不许取;orange 表示盘中是否有橘子,初值同样为 0,orange=1 表示盘子中由橘子允许取。 则用伪程序表示如下: semapore plate=1,apple=0,orange=0;
dad(){
while(1){
prepare an apple;
P(plate); //互斥向盘中取、放水果
put the apple on the plate; //向盘中放苹果
V(apple); // 允许取苹果
}
}
mom(){
while(1){
prepare an orange;
P(plate);
put the orange on the plate;
V(orange);
}
}
son(){
while(1){
P(orange); //互斥从盘中取橘子
take an orange from the plate;
V(plate); //允许向盘中放、取水果
eat the orange;
}
}
daughter(){
while(1){
P(apple);
take an aplle from the plate;
V(plate);
eat the apple;
}
}
二、读者-写者问题
问题描述:
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程同时访问共享数据时则可能导致数据不一致的错误,因此: ① 允许多个读者可以同时对文件执行读操作; ② 只允许一个写者往文件中写信息; ③ 任一写者在完成写操作之前不允许其他读者进程或写者工作; ④ 写者执行写操作前,应让已有的读者和写者全部退出。
问题分析:
1)关系分析,读者和写者互斥的,写者和写者互斥,读者和读者之间不互斥。 2)思路整理:两个进程,读者和写者。由于写者和其他进程都互斥,因此可用互斥信号量的P操作、V操作解决;读者则较为复杂,与写者互斥的同时,又要与其他读者同步,需要一个计数器用于判断当前是否有读者读文件:当有读者时,写者不能写文件,此时读者一直占用文件直到退出,写者才可以写文件;同时,不同读者对计数器的访问也是互斥的。 3)信号量设置:设置 count 信号量为计数器,初值为 0;mutex 为互斥信号量,用于保护更新 count 变量时的互斥;互斥信号量 rw 用于保证读者和写者互斥访问。
①有瑕疵的算法
② 完善的算法
```
int count=0;
semaphore mutex=1;
semaphore rw=1;
semaphore w=1; // 实现写者优先
writer(){
while(1){
P(w); // 在无写进程请求时进入
P(rw); // 互斥访问共享文件
writing
V(rw); // 释放共享文件
V(w); // 恢复对共享文件的访问
}
}
reader(){
while(1){
P(w);
P(mutex); // 互斥访问 count 变量
if(count==0) // 当第一个读进程读共享文件时
P(rw) // 阻止写进程
count++;
V(mutex); // 释放互斥变量 count
V(w);
reading;
P(mutex);
count--;
if(count==0) // 当最后一个读进程读完共享文件
V(rw); // 允许写进程写
V(mutex);
}
}
```
三、哲学家进餐问题
问题描述:
一张圆桌上坐着5名哲学家,每两名哲学家之间的桌子上摆着一根筷子,两根筷子之间是一碗米饭。哲学家倾注毕生精力于思考和进餐,哲学家思考时不影响其他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子——一根一根地拿起。若筷子已在他人手上,则需要等待。饥饿地哲学家只有同时拿到了两根筷子才能开始进餐,进餐完毕,放下筷子继续思考。
问题分析:
1)5 名哲学家与左右邻座对其中间的筷子的访问时互斥关系。 2)思路整理:显而易见,5 个哲学家对应5 个进程,问题解决的关键就是如何让一名哲学家拿到左右两根筷子而不造成死锁或饥饿现象。解决方法有两个:一是让他们同时拿两根筷子;二是对每名哲学家的动作制定规则,避免饥饿或死锁现象的发生。 3)信号量设置:互斥信号量数组 chopstick[5]={1,1,1,1,1},用于对 5 个筷子的互斥访问;哲学家编号顺序:0~4,哲学家 I 左边筷子的编号为 i,哲学家右边筷子的编号为(i+1)%5。
① 有缺陷算法:
```
semaphore chopstick[5]={1,1,1,1,1};
Pi(){
do{
P(chopstick[i]); //取左边筷子
P(chopstick[(i+1)%5]);// 取右边筷子
eat;
V(chopstick[i]); //放回左边筷子
V(chopstick[(i+1)%5]);// 放回右边筷子
think;
}while(1);
}
```
此算法存在的问题就是,当5名哲学家都想要进餐并分别拿起左边的筷子时,所有的筷子将被拿光,等到他们再想拿起右边的筷子时,就会发生全被阻塞,出现死锁
。若要避免此种情况,可以增加限制条件,如至多允许4名哲学家同时进餐;仅当一名哲学家左右两边筷子都可以用时,才允许他抓起筷子;对哲学家顺序编号,奇数号哲学家先拿起左边筷子,然后拿起右边的,而偶数哲学家相反。
②完善的算法
```
semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex=1;
Pi(){
do{
P(mutex); // 在取筷子前获得互斥量
P(chopstick[i]); //取左边筷子
P(chopstick[(i+1)%5]);// 取右边筷子
V(mutex); // 释放取筷子的信号量
eat;
V(chopstick[i]); //放回左边筷子
V(chopstick[(i+1)%5]);// 放回右边筷子
think;
}while(1);
}
```
四、吸烟者问题
问题描述:
假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但要卷起一支烟,抽烟者需要三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉已完成,此时供应者就会将另外两种材料放到桌子上,循环反复如此。
问题分析:
上一篇 下一篇