关于叫号类的PV操作总结

来源:互联网 发布:淘宝动态评分怎么提高 编辑:程序博客网 时间:2024/05/22 01:41

关于叫号类的PV操作总结

@(OS)

先分析一道题目。

面包师傅有很多面包,由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);        为顾客服务;    }}

也可以最直接的根据场景理解:顾客进来,最终目的是获得服务。但为了达到这个目的,需要去叫号,但是这里强调了有空座位时才去取号。所以,顾客要三样东西:座位,号码,加服务。银行就一个窗口,减少已经拿到号码的顾客,增加空座位,并提供服务。这样的流程理顺了,则问题可解。

2 0
原创粉丝点击