吸烟者问题

假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供应者就会放另外两种材料再桌上,这个过程一直重复(让三个抽烟者轮流地抽烟)

以上图为例,供应者向桌上摆放烟草和纸两种材料,缺少这两种材料的三号吸烟者就会取走材料吸烟,在吸烟结束后会提醒供应者放新的材料在桌上

根据题目我们直到,放在桌上的材料一共有三种组合方式

  1. 纸和胶水(order1)会被一号吸烟者取走
  2. 烟草和胶水(order2)会被二号吸烟者取走
  3. 烟草和纸(order3)会被三号吸烟者取走

本题可以看作是存在一个生产者和多个消费者的问题,同时生产者所生产的物品并不相同

关系分析

找出题目中描述的各个进程,分析同步互斥关系

  • 互斥关系:桌子可以抽象为容量为1的缓冲区,需要互斥访问
  • 同步关系:桌上有组合一时第一个抽烟者取走物品
  • 同步关系:桌上有组合二时第二个抽烟者取走物品
  • 同步关系:桌上有组合三时第三个抽烟者取走物品
  • 同步关系:抽烟者完成吸烟后发出完成信号,供应者将下一组组合放在桌上

整理思路

根据各个进程的操作流程确定PV操作的大致顺序

对于互斥关系的处理只要遵循在访问临界资源前对临界资源上锁,访问之后解锁即可

对于同步关系的处理要遵循“前V后P”原则,必须先执行的操作后执行V操作,必须后执行的操作执行前执行P操作

设置信号量

由于本题目中缓冲区大小为1,同一时间只可能至多有一个进程访问互斥资源,所以不需要设置互斥信号量mutex

同步信号量的设置要看对应资源初始值进行赋值

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
semaphore offer1=0; //桌上组合一的数量
semaphore offer2=0; //桌上组合二的数量
semaphore offer3=0; //桌上组合三的数量
semaphore finish=0; //抽烟是否完成
int i=0; //用于实现三个吸烟者轮流吸烟

//供应者进程
provider(){
while(1){
if(i==0){
将组合一放桌上
V(offer1); //题型一号吸烟者吸烟
}else if(i==1){
将组合二放桌上
V(offer2); //题型二号吸烟者吸烟
}else{
将组合三放桌上
V(offer3); //题型三号吸烟者吸烟
}
i=(i+1)%3; //实现让三个吸烟者轮流吸烟
P(finish); //等待吸烟者吸烟完成后继续放组合
}
}

//一号吸烟者进程
smoker1(){
while(1){
P(offer1); //等待组合一放到桌上
从桌上拿走组合一,吸烟
V(finish); //题型供应者提供新组合
}
}

//二号吸烟者进程
smoker2(){
while(1){
P(offer2); //等待组合二放到桌上
从桌上拿走组合二,吸烟
V(finish); //题型供应者提供新组合
}
}

//三号吸烟者进程
smoker3(){
while(1){
P(offer3); //等待组合三放到桌上
从桌上拿走组合三,吸烟
V(finish); //题型供应者提供新组合
}
}