一道2013年的825考研PV操作真题:
为了提高浴室利用率,某大学校园采用所有的公共浴室不分男女了,使用规则是:如果浴室空,男女均可进入;如果浴室中已经有女生,则其他女生可以进入,男生不能进入,反之亦然;假设每个浴室最多容纳十人同时洗澡,试用PV操作来正确管理男女对公共浴室的共享过程。
虽然这道题很不正经,最初我也很不屑做这道题,打上眼很明显的读者写者问题,只不过就是把写者变成了读者使之变成了双读者问题而已,但本人驽钝,做了两个小时才搞出了一些眉目。PS:不得不说,PV操作的逻辑题,当你觉着做不出来的时候就不要硬扣了,因为你已经陷进逻辑陷阱里面了。
int countg=0 //记录浴室中girl人数的信号量
int countb=0 //记录boy的
mutex = 1 //互斥量
/*
首先描述一下一个boy整个洗澡的过程,答题可分为三个过程:
来到浴室门口
if(浴室里没有girl)
if(浴室里boy人数超过十人)
离开门口坐在门边的板凳上
继续在门口检查,直到发现浴室没有girl并且boy人数不超过十人为止
else
登记一下count++
离开门口
进入浴室
else
离开门口门边的板凳上
继续在门口检查,直到发现浴室里没有girl为止
------------------------------
洗澡
------------------------------
出门登记一下count--
*/
Boy:
while(1){
p(mutex)
if(countg == 0){
if(countb >10){
v(mutex)
}
else{
countb++
v(mutex)
break;
}
}
else{
v(mutex)
}
}
----
洗澡
----
p(mutex)
countb--
v(mutex)
Girl:
while(1){
p(mutex)
if(countb == 0){
if(countg >10){
v(mutex)
}
else{
countg++
v(mutex)
break;
}
}
else{
v(mutex)
}
}
----
洗澡
----
p(mutex)
countg--
v(mutex)
化繁去简,本题虽然是读写者模型,但是要求比读写者严格,在最原始的读写者模型中,其实是存在读者优先的,代码如下(转自http://blog.sina.com.cn/s/blog_a3eacdb20101ct0c.html):
int rc=0; //用于记录当前的读者数量
semaphore rc_mutex=1; //用于对共享变量rc 操作的互斥信号量
semaphore write=1; //用于保证读者和写者互斥地访问的信号量
void reader()
do{
P(rc_mutex); //开始对rc共享变量进行互斥访问
rc ++; //来了一个读进程,读进程数加1
if (rc==1) P(write); //如是第一个读进程,判断是否有写进程在临界区,
//若有,读进程等待,若无,阻塞写进程
V(rc_mutex); //结束对rc共享变量的互斥访问
读文件;
P(rc_mutex); //开始对rc共享变量的互斥访问
rc--; //一个读进程读完,读进程数减1
if (rc == 0) V(write); //最后一个离开临界区的读进程需要判断是否有写进程//需要进入临界区,若有,唤醒一个写进程进临界区
V(rc_mutex); //结束对rc共享变量的互斥访问
} while(1)
void writer()
do{
P(write); //无读进程,进入写进程;若有读进程,写进程等待
写文件;
V(write); //写进程完成;判断是否有读进程需要进入临界区,
//若有,唤醒一个读进程进临界区
} while(1)
可以看到,这里读者在有限条件count==0下掌握了写者的write的同步信号量,所以写者必须只能等读者全部读完后才能进入进程,否则就会被阻塞在该信号量上,但注意,如果读者源源不断,而写者想要访问,写者因为write的原因永远不会被随机调用。但男女浴室则不同,这相当于一个有着数量限制而且必须是进程公平竞争的一个PV操作。
公平竞争即意味着,两种类型的进程需要用同一个互斥量来访问某些共享资源,如果两边用不同互斥量则会导致某些不可知的隐患(具体情况具体分析)
而不公平则意味着,一类进程掌握着另一进程的某信号量的P操作或者V操作
所以在我看来,如若要实现公平竞争,就不能存在同步信号量,全用公共的互斥信号量和记录性信号量来完成整个共享过程
这里我用mutex该信号量来保护countg和countb,在实际生活中就相当于,浴室门口同时只能给一个人访问,不能说男生或者女生谁有优先权使用这个门口,然后根据while循环和if判断浴室里人员的种类和人数来决定能否进入临界区。
但这题我连同类进程间因人数溢过十人的情况都没有使用同步信号量,是因为我构造了一个循环,在实际生活中的意义就是,男生在门口观察到浴室没有女生而且男生人数超过十人,他就去干别的事情了,过一阵他又要回来重新干一遍他之前干过的事情。
如果你想要很多同步量去构建一个公平竞争的坏境,那真的有点天狗吃月,因为同步量的P操作属于一个在0之上的信号量递减操作,一旦其减至0,所有调用同步量的进程都会被阻塞住。
这里给出一个读写者,假设有n个写者和n个读者,公平的PV操作:
int countW=0
int countR=0
mutex=1
Reader:
while(1){
P(mutex)
if(countW == 0){
countR++
V(mutex)
break;
}
V(mutex)
}
Read file
P(mutex)
countR--
V(mutex)
Writer:
while(1){
P(mutex)
if(countR == 0){
countW++
V(mutex)
break;
}
V(mutex)
}
Write file
P(mutex)
countW--
V(mutex)
公平即不会响应所有请求,如果没有满足你的条件,你就继续循环等待被调用,直到满足了你的条件为止