pv经典例题 - wolai 笔记

1.阅览室登记

问题

有一阅览室,共有100个座位。读者进入时必须先在一种登记表上登记,该表为每一座位列一个表目,包括座号和读者姓名。读者离开时要注销掉登记内容。试用P、V原语描述读者进程的同步问题。

关系分析

  • 同步关系:座位的使用
  • 互斥关系:登记、注销互斥操作

代码

semaphore empty = 100; // 记录空座位数量
semaphore mutex = 1;    // 互斥信号量,互斥访问登记和注销操作
void reader()
{
    while(true)
    {
        P(empty);
        P(mutex);
        // 登记
        V(mutex);
        // read
        P(mutex);
        // 注销
        V(mutex);
        V(empty);
    }
}

2.动物存放

问题

有一只铁笼子,每次只能放入一只动物,猎手向笼子里放入老虎,农民向笼子里放入猪;动物园等待取笼子里的老虎,饭店等待取笼子里的猪。现请用P、V操作写出能同步执行的程序。

关系分析

  • 同步关系
    • 放 --> 取

代码

信号量
semaphore box = 1;      // 记录笼子是否为空
semaphore tiger = 0;    // 老虎的同步信号量
semaphore pig = 0;      // 猪的同步信号量
猎人
void hunter()
{
    while(true)
    {
        P(box);
        // 放入老虎
        V(tiger);
    }
}
农民
void famer()
{
    while(true)
    {
        P(box);
        // 放入猪
        V(pig);
    }
}
动物园
void zoo()
{
    while(true)
    {
        P(tiger);
        // 取走老虎
        V(box);
    }
}
饭店
void restaurant()
{
    while(true)
    {
        P(pig);
        // 取走猪
        V(box);
    }
}

3.售票

问题

某车站售票厅,任何时刻最多可容纳20名购票者进入,当售票厅中少于20名购票者时则厅外的购票者可立即进入,否则需在外面等待。若把一个购票者看作一个进程,请回答下列问题 (1) 用PV操作管理这些并发进程时,应怎样定义信号量?写出信号量的初值以及信号量各种取值的含义。 (2) 若欲购票者最多为n个人,写出信号量可能的变化范围(最大值和最小值)。

答案

(1)定义一信号量S,初始值为20。
  • S>0,S的值表示可继续进入售票厅的人数;
  • S=0,表示售票厅中已有20名顾客(购票者);
  • S<0,|S|的值为等待进入售票厅的人数。
    (2)由于s的值表示的是在售票厅有多少个座位,因此最大值为s(表示没有人)最小值为s-n(根据n来决定)

4.司机售票员

问题

在公共汽车上,司机负责开车、停车和驾驶,售票员负责门的开门、关门和售票。基本操作规则是只有停车后,售票员才能开门;只有售票员关门后,司机才能开车。汽车初始状态处于行驶之中。当只有1个司机、2个售票员、2个门、每个售票员负责一个门时的协调操作。请使用P、V原语实现售票员与司机之间的协调操作说明每个信号量的含义、初值和值的范围。

关系分析

同步信号
  • 售票员关门 ---> 司机开车
  • 司机停车 ---> 售票员开门

代码

信号量
semaphore close1 = 1, close2 = 1; // 关门同步信号量
semaphore open1 = 0, open2 = 0;   // 开门信号量
司机
void driver()
{
    while(true)
    {
        P(close1);
        P(close2);
        // 启动车辆
        // 正常行使
        // 到站停车
        V(open1);
        V(open2);
    }
}
售票员1
void seller1()
{
    while(true)
    {
        P(open1);
        // 开门
        // 关门
        V(close1);
        // 售票
    }
}
售票员2
void seller2()
{
    while(true)
    {
        P(open2);
        // 开门
        // 关门
        V(close2);
        // 售票
    }
}

5.取号叫号

问题

某银行有人民币储蓄业务,有n个柜员负责,有1台取号机。每个顾客进入银行后先取一个号,若有人取号则需等他人取完后才能取。取到号后等待叫号,当一个柜员人员空闲下来就叫下一个号。试用P、V操作正确编写柜台人员和顾客进程的程序。

关系分析

互斥信号量
  • 顾客取号
  • 服务人员叫号
同步信号量
  • 取号 --- > 等待被叫号
  • 服务完 ---> 叫号

代码

信号量
semaphore mutex = 1;    // 同步信号量
semaphore serviceEmpty = 3; // 柜员服务空闲信号量
semaphore serviceFull = 0;  // 柜员服务满的信号量,若大于3,则表示等待人数为 n-3
顾客
void customer()
{
    while(true)
    {
        P(mutex);
        // 取号
        V(mutex);
        // 等待叫号
        V(serviceFull);
        P(serviceEmpty);
    }
}
柜员
void servicer()
{
    while(true)
    {
        P(serviceFull);
        P(mutex);
        // 叫号
        V(mutex);
        // 服务
        V(serviceEmpty);
    }
}

6.听音乐问题

问题

在一间酒吧里有三个音乐爱好者队列,第一个音乐爱好者只有随身听,第二个只有音乐磁带,第三个只有电池,而要听音乐就必须有随身听,音乐磁带和电池这三种物品。酒吧老板一次出售这三种物品中的任意两种,当一名音乐爱好者得到这三种物品并听完乐曲后,酒吧老板才能再一次出售这三种物品中任意两种,于是第二名音乐爱好者得到这三种物品。并开始听乐曲,全部买卖就这样进行下去。使用P、V操作正确解决这一买卖。

关系分析

与抽烟者问题类似 同步关系:
  • 老板出售物品 --> 三个爱好者
  • 爱好者使用完成 --> 老板出售下一个

代码

信号量
semaphore comeIn = 1;   // 同步顾客是否来,每次只能服务一个顾客
semaphore stereo = 0;   // 随身听同步信号量,初始未生产,为0
semaphore tape = 0;     // 磁带听同步信号量,初始未生产,为0
semaphore battle = 0;   // 电池听同步信号量,初始未生产,为0

// 标识老板是否有资源
bool stereoFlag = 0;
bool tapeFlag = 0;
bool battleFlage = 0;
老板
void boss()
{
    while(true)
    {
        P(comeIn);
        if(stereoFlag && tapeFlag)
            V(battle);
        else if(stereoFlag && battleFlag)
            V(tape);
        else
            V(stereo);
    }
}
第一个音乐爱好者:需要电池和磁带,自己有随身听
void hobby1()
{
    while(true)
    {
        P(stereo);
        // 购买物品,听音乐
        V(comeIn);  // 我买完了,老板可以接待下一个了
    }
}
第二个音乐爱好者:需要电池和随身听,自己有磁带
void hobby1()
{
    while(true)
    {
        P(tape);
        // 购买物品,听音乐
        V(comeIn);  // 我买完了,老板可以接待下一个了
    }
}
第三个音乐爱好者:需要随身听和磁带,自己有电池
void hobby1()
{
    while(true)
    {
        P(battle);
        // 购买物品,听音乐
        V(comeIn);  // 我买完了,老板可以接待下一个了
    }
}

Comment