操作系统-关于叫号类的PV操作总结

 

原文  http://blog.csdn.net/u011240016/article/details/53395370
时间  2016-11-29

先分析一道题目:

面包师傅有很多面包,由n个推销人员推销。每个顾客进店后取一个号,并且等待叫号。当一个销售人员空闲下来时,就叫下一个号。设计一个使销售人员和顾客同步的算法。
分析:需要理解的是这个场景中的过程,抽象出进程的概念,再用信号量约束。
在这个场景中,主要是用号码进行约束。当取号时,这个号码只能给到一个人,因此要互斥访问。当按照号码叫号时,因为有n个推销员,所以号码也需要被互斥访问。
所以针对顾客取的号,和销售员待叫的号,需要设置两个变量控制访问。
即:
 
int i = 0, j = 0;
semaphore mutex_i = 1,mutex_j = 1;
Consumer()
{
    进入面包店;
    P(mutex_i); //互斥访问号码i
    取号 i;
    i++;//正常逻辑下,号码要自增
    V(mutex_i); //释放,可用于下一次的叫号控制
    等待叫号i并购买面包
}
Seller()
{
    while1)
    {
        P(mutex_j);//互斥访问当前叫号
        if(j < i)//只要有未叫的号,就不停止
        {
            叫号j;
            j++;
            V(mutex_j);
            销售面包;
        }
        else
        {
            V(mutex_j);
            休息;
        }
    }
}
单独看这个,容易形成的思维定势是见到号码,一定对号码进行互斥访问,其实不然,只要找到场景中能够约束进程或过程同步或互斥的变量都可以,并不是片面的都是对号码进程控制。
再举一个类似但不相同的控制思路。
(2011.45)某银行提供一个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空闲座位,则到取号机上取一个号,等待叫号。取号机每次仅允许一个顾客使用。当营业员空闲时,通过叫号选取一位顾客,并为其服务。顾客和营业员的活动过程描述如下:
cobegin
{
    process 顾客i
    {
        从取号机获取一个号码;
        等待叫号;
        获取服务;
    }
    process 营业员
    {
        while(1)
        {
            叫号;
            为客户服务;
        }
    }
} coend
思考:在这样的场景中,需不需要可以对叫的号码和取的号码进行互斥访问?
为什么要对获取号码进行互斥访问?答案是不让人取同一个号码。
为什么要对叫的号进行互斥访问?答案是防止不同的人叫了同一个号。
OK,回到这里的场景,控制叫号机的互斥访问就能控制取号的不同。
因为只有一个窗口服务,因此不存在多人叫同一个号的情况,因此不用对叫的号进行互斥访问。
推演来看,如果是多个服务窗口,就需要对叫的号进行互斥访问。也即添加一个mutex进行互斥即可。
再看座位,我们想为什么在生产者消费者的模型中,要设置一个full和一个empty跟踪,明明已经知道了总数,设置一个full或者empty不就可以了吗?是的,当然也行,只不过用的是总数减去其中一个得到另一个换算,思想是一个意思:用变量跟踪状态。
那无论是缓冲区还是座位,只要两个进程改变的方向不一样,那么就设full和empty来跟踪即可。
顾客和营业员之间是同步关系,在第一个例子中,其实用的是文字描述两个进程之间的同步,而没有用信号量做,所以不是严谨的答案,只是作为一个引例说明号码这件事情。
这里严格来做,就需要设置一个同步变量,同步变量的初始值为0,区别于互斥。
这样,可以抽出两个简化模型:
  • 互斥:取号机,mutex=1控制
  • 同步:顾客需要获得座位等待叫号。营业员空闲时,选取一个顾客为其服务。空座位的有无影响等待顾客数量。顾客的有无决定营业员是否可以服务。设置信号量和full来实现两个同步关系。设置service构成顾客与营业员何时开始服务的同步关系。
semaphore empty = 10; //空位数初值
semaphore full = 0; //已使用
semaphore mutex = 1; //互斥访问叫号机
semaphore service = 0; //控制服务同步关系
process 顾客i
{
    P(empty); //等空位,在营业员那边V,所以是一个同步关系
    P(mutex);
    从取号机取号;
    V(mutex);
    V(full);//营业员那边在P,也是一个同步关系
    P(service); //营业员那边在V,同步关系
}
process 营业员
{
    while(1)
    {
        P(full); 
        V(empty);
        V(service);
        为顾客服务;
    }
}

 

posted @ 2019-04-15 21:05  扬羽流风  阅读(1040)  评论(0编辑  收藏  举报