问答题 某银行的营业厅有多个柜员窗口,可以同时办理业务。银行的营业厅中安排有n张座椅供储户休息等候。每个储户在进入营业厅时会在排队机上取得一个号码,若此前没有客户,则排队机就会唤醒一个柜员为储户服务,当没有储户时柜员便可以休息。若储户较多,则所有柜员均会参与服务,当排队储户数超过柜员数时,没有被服务的储户便会在座椅上休息,并等候叫号。当座位满时,再进入营业厅的储户不再从排队机上获取号码,会离开去找另外的营业厅。若将银行的柜员和储户的行为看成是不同类型的进程,请设一个程序,利用信号量来完成上述操作,用类C语言写出程序。

【正确答案】此类题目在考试中也比较多见,类似的还有睡眠的理发师等。因此,掌握此类题目的基本要点是解决此类题目的关键。本题从读者和写者的基本原理出发,对等候的储户数加以限制。从资源角度看,柜员是资源,座椅也是资源。那么,设置柜员的信号量为teller,初始为0,柜员一上岗则作V操作,以提供资源。储户的信号量为customer,初始为0,表示储户尚未进入营业厅。mutex为排队机,也是座椅的互斥量,柜员和储户均可以对此操作。
设信号量teller,customer和mutex其中waiting是整型量,表示排队的储户数,其初始为0,最大不超过n。
#define CHAIRS=N
//座椅数, 也是最多排队的储户数
typedef int semaphore;
//定义信号量
semaphore teller=0;
//等待储户的柜员数
semaphore customer=0;
//等待服务的储户数
semaphore mutex=0;
//对排队机操作的互斥量
int waiting=0;
//等待的储户数
void teller()
{
while(TRUE) {//并发调度
P(customer);
//查看有无储户
P(mutex );
//需要获得排队机的控制权
waiting=waiting-1;
//将等候的顾客数减1
V(teller);
//提供1个可服务的柜员
V(mutex);
//释放排队机
service();
//为储户服务
}
}
void customer()
//储户进程
{
P(mutex);
//先获得排队机
if(waiting<CHAIRS){
//若还有座椅则取号
waiting=waiting+1;
//取号,占用座椅等待叫号
V(customer);
//告知系统储户加1
V(mutex);
//释放排队机
P(teller);
//看是否有空闲柜员
Serviced();
//进入窗口被服务
{else{
//若没有座椅了, 则不取号
V(mutex);
//不取号, 释放排队机
}
}
//离开
[注意] 本题中,柜员是具有循环的。即while(TRUE)的语句,储户就没有,原因是储户是随时到达的,柜员是等候储户到来并服务的,如果储户进程也采用并发调度,则顾客就不可能为0,这与实际情况不同,所以在此是不需要的。
对于柜员来说,当开启一个窗口即会调用一次柜员进程,所以,柜员应该一直运行,直到其下班(下班作为边界条件在此并不讨论)。若多个柜员上岗,则就多次调用柜员进程,但是,排队机和座椅是不变的,柜员可能会增加,这会加快对顾客的服务,所以,实际上在营业厅里最多的顾客数应该是柜员数加上座椅数,最少当然是0。
【答案解析】