吸烟者问题

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

分析:

这是一种可以生产多种产品的单生产者和多消费者问题,每次生产者只能放两种材料到桌子上,那这就存在着互斥问题,我们可以将桌子抽象为容量为1的缓冲区,那可能会问,我每次放两个东西上去啊,容量怎么能是1呢,在这里我们应该看成组合关系,我们每次是放一个组合上去

1
2
3
组合一:纸+胶水
组合二:烟草+胶水
组合三:烟草+纸

同步关系(从事件角度来考虑)

1 桌子上有组合一 -> 第一个抽烟者取走东西

2 桌子上有组合二 -> 第二个抽烟者取走东西

3 桌子上有组合三 -> 第三个抽烟者取走东西

4 发出信号 -> 供应者将下一组合放到桌子上

那对应的四个同步信号量就应该是

1
2
3
4
semaphore offer1 = 0;
semaphore offer2 = 0;
semaphore offer3 = 0;
semaphore finish = 0;

其中finish表示发出完成信号的数量,刚开始是0

那对应的PV操作如下图所示

图示

根据多生产者多消费者分析出的结论,这个抽烟者问题也是当缓冲区容量为1时,可不设置互斥信号量也能实现互斥

代码实现:

`C++
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 if(i==2){
将组合三在桌上;
V(offer3);
}
i = (i+1)%3;//实现 0 1 2循环
P(finish);//若写在最上面就一下子就阻塞了,要等到放完东西再检查有没有完成信号
}
}
smoker1(){
while(1){
P(offer1);
从桌子上拿走组合一,卷烟抽掉;
V(finish);
}
}
smoker2(){
while(1){
P(offer2);
从桌子上拿走组合二,卷烟抽掉;
V(finish);
}
}
smoker3(){
while(3){
P(offer3);
从桌子上拿走组合三,卷烟抽掉;
V(finish);
}
}

-------------本文结束感谢您的阅读-------------