用信号量解决同步互斥问题 - 读者写者问题

综述

OS老师上课在讲解读者和写者问题时,一般会按照三个层次展开讲解。根据信号量的分布和控制逻辑,大体可以将读者-写者问题按由易到难分成如下这三大类:

  1. 读者优先,课本上的写法属于占位后读优先,与占位前读优先、绝对读优先一起,均归于此类;
  2. 读写公平,根据读写进程的到达先后顺序严格执行FCFS调度;
  3. 写优先,包括占位前写优先、占位后写优先和绝对写优先。

本文将从这三类中选择关键的例子以“注解+代码”的形式按序剖析。

Cases

读优先 (占位后读优先)

rw用于实现写写互斥,读写互斥,但也导致了读读互斥。

ReaderCnt的相关操作在写写互斥和读写互斥的基础上实现了读读不互斥,同时也实现了占位后读优先。

mutex1用于对ReaderCnt的读写操作提供互斥保护。

int ReaderCnt=0;
Semaphore mutex1=1, rw=1;

Reader(){
    P(mutex1);
    ReaderCnt++;	
    if(ReaderCnt==1) P(rw);
    V(mutex1);

    Reading();

    P(mutex1);
    ReaderCnt--;
    if(ReaderCnt==0) V(rw);
    V(mutex1);
}

Writer(){
    P(rw);
    Writing();
    V(rw);
}

绝对读优先 (满足占位前后均读优先)

w用于在写的最外层再建立一个父队列,这样rw的队列中不会出现写。不论之前到达了多少写,任意首次到达的读均能够直接被放到rw首部,即"总能跳过所有写"。待正在执行的写进程退出后,立刻执行这个首次到达的读,即读占位,从而实现占位前优先。

int ReaderCnt=0;
Semaphore mutex1=1, rw=w=1;

Reader(){
    P(mutex1);
    ReaderCnt++;	
    if(ReaderCnt==1) P(rw);
    V(mutex1);

    Reading();

    P(mutex1);
    ReaderCnt--;
    if(ReaderCnt==0) V(rw);
    V(mutex1);
}

Writer(){
    P(w);
    P(rw);
    Writing();
    V(rw);
    V(w);
}

读写公平 (满足FCFS调度)

q用于实现一个读和写的FIFO公共队列,这个队列中进程的顺序与进程的到达次序一致,从而实现FCFS,即读写公平。

Reader()中V(q)的位置很巧妙:首先,V(q)应在V(mutex1)之后,这是由对称性决定的,因为P(q)恰好在P(mutex1)之前,这个对称性一旦被破坏,会进一步使mutex1的功能也被破坏;另一方面,Reading()允许并行执行,若把V(q)放到Reading()之后将会破坏这一条件,使得读不能并行。综上,V(q)应放在第一个V(mutex1)和Reading()之间。

扩展:如果把这里的Reading()换成Writing(),那么V(q)的位置可以放到Writing()之后,或者Reader()的最末尾。因为Writing()本来就不能并行,上段中的第二个位置约束不再成立。

int ReaderCnt=0;
Semaphore mutex1=1, rw=q=1;

Reader(){
    P(q);
    P(mutex1);
    if(ReaderCnt==0) P(rw);
    ReaderCnt++;	
    V(mutex1);
    V(q);

    Reading();

    P(mutex1);
    ReaderCnt--;
    if(ReaderCnt==0) V(rw);
    V(mutex1);
}

Writer(){
    P(q);
    P(rw);
    Writing();
    V(rw);
    V(q);
}

绝对写优先 (满足占位前后均写优先)

类似地,ReaderCnt和wpao实现占位后优先,wpbo实现占位前优先。

wpbo = Write Priority Before Occupation,wpao = Write Priority After Occupation。

扫描二维码关注公众号,回复: 11263365 查看本文章
int ReaderCnt=0, WriterCnt=0;
Semaphore mutex1=mutex2=1, rw=wpbo=wpao=1;

Reader(){
    P(wpbo);
    P(wpao);
    P(mutex1);
    ReaderCnt++;
    if(ReaderCnt==1) P(rw);
    V(mutex1);
    V(wpao);
    V(wpbo);

    Reading();

    P(mutex1);
    ReaderCnt--;
    if(ReaderCnt==0) V(rw);
    V(mutex1);
}

Writer(){
    P(mutex2);
    WriterCnt++;
    if(WriterCnt==1) P(wpao);
    V(mutex2);

    P(rw);
    Writing();
    V(rw);

    P(mutex2);
    WriterCnt--;
    if(WriterCnt==0) V(wpao);
    V(mutex2);
}

猜你喜欢

转载自blog.csdn.net/Flying_Dutch/article/details/106125192