操作系统之——进程同步经典问题

点击打开链接生产者消费者问题

一个生产者,一个消费者,公用一个缓冲区

定义两个同步信号量:
empty——表示缓冲区是否为空,初值为1。
full——表示缓冲区中是否为满,初值为0。
生产者进程
while(TRUE){
生产一个产品;
     P(empty);
     产品送往Buffer;
     V(full);
}
消费者进程
while(TRUE){
P(full);
   从Buffer取出一个产品;
   V(empty);
   消费该产品;

一组生产者,一组消费者,公用n个环形缓冲区

定义四个信号量:
empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。
设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。
 
生产者进程
while(TRUE){
     生产一个产品;
     P(empty);
     P(mutex1);
     产品送往buffer(in);
     in=(in+1)mod n;
     V(mutex1);
     V(full);
     }
消费者进程
while(TRUE){
 P(full);
   P(mutex2);
   从buffer(out)中取出产品;
   out=(out+1)mod n;
   V(mutex2);
   V(empty);

哲学家进餐问题

利用AND 型信号量机制实现

semaphore chopstick[5]={1,1,1,1,1}; 
void philosopher(int I) 

while(true) 

think(); 
P(chopstick[(I+1)]%5,chopstick[I]); 
eat(); 
V(chopstick[(I+1)]%5,chopstick[I]); 

}

读者—写者问题

要求:
(1)允许多个读者同时执行读操作;
(2)不允许读者、写者同时操作;
(3)不允许多个写者同时操作。
Reader和Writer的同步问题分为读者优先、弱写者优先(公平竞争)和强写者优先三种情况,它们的处理方式不同。

(1)读者优先

对于读者优先,应满足下列条件:
如果新读者到:
①无读者、写者,新读者可以读;
②有写者等待,但有其它读者正在读,则新读者也可以读;
③有写者写,新读者等待。
如果新写者到:
①无读者,新写者可以写;
②有读者,新写者等待;
③有其它写者,新写者等待。
单纯使用信号量不能解决读者与写者问题,必须引入计数器rc 对读进程计数;rc_mutex 是用于对计数器rc 操作的互斥信号量;write表示是否允许写的信号量;于是读者优先的程序设计如下:
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)
读者优先的设计思想是读进程只要看到有其它读进程正在读,就可以继续进行读;写进程必须等待所有读进程都不读时才能写,即使写进程可能比一些读进程更早提出申请。该算法只要还有一个读者在活动,就允许后续的读者进来,该策略的结果是,如果有一个稳定的读者流存在,那么这些读者将在到达后被允许进入。而写者就始终被挂起,直到没有读者为止。

(2)写者优先1

为了解决以上问题,写者优先1的设计思想是在一个写者到达时如果有正在工作的读者,那么该写者只要等待正在工作的读者完成,而不必等候其后面到来的读者就可以进行写操作。注意,该算法当一个写者在等待时,后到达的读者是在写者之后被挂起,而不是立即允许进入。
在读者优先的算法的基础上增加了一个排队信号量read,读、写进程在每次操作前都要等待read信号量。写者优先1的程序设计如下:
int rc=0;                                                         //用于记录当前的读者数量
semaphore rc_mutex=1;                               //用于对共享变量rc 操作的互斥信号量
semaphore wc_mutex=1;                              //用于保证读者和写者互斥地访问的信号量
semaphore write=1;                                   //用于保证读者和写者互斥地访问的信号量
semaphore read=1;                                   //用于保证在写进程封锁其后续的读进程的信号量
 
void reader()     
do{
P(read);                                //若有写进程,后续读进程等待,在read队列上排队
P(rc_mutex);                             //开始对rc共享变量进行互斥访问
rc++;                                    //来了一个读进程,读进程数加1
if rc=1 then  P(write);                  //第一个读进程需要判断是否有写进程在临界区,若有,
//读进程需要等待,若没有,阻塞写进程
V(rc_mutex);                           //结束对rc共享变量的互斥访问
V(read);                               //从 read队列中唤醒一个进程
Reading the file;
P(rc_mutex);                            //开始对rc共享变量的互斥访问
rc--;                                    //一个读进程读完,读进程数减1
if rc=0 then  V(write);                  //最后一个离开临界区的读进程需要判断是否有写进程
/                               //需要进入临界区,若有,唤醒一个写进程进临界区
V(rc_mutex);                             //结束对rc共享变量的互斥访问
}
 
void  writer()          
do{
P(read);                               //无读进程,写进程进入;有读进程,在read排队,其后
//到来的读进程排在该队列写者之后
P(write);                               //若有读进程在读,等待现有读进程读完才可写
Writeing the file;   
V(write);                              //写进程完成;判断是否有读进程需要进入临界区,若有,
             //唤醒一个读进程进临界区
V(read);                              //从 read队列中唤醒一个进程
注意,该算法当第一个写者已经P(read)后,read变为0,来了N个读者,他们都停留在它的P(read)这一句。那么会出现什么问题呢?此时,如果原来的写者完成了,紧接又来了一个写者,写者需要P(read)。这个时候,由于N个读者都已经在这个写者之前P(read)了,所以这个写者需要排队排在这N个读者分别都得到P(read)后才能得到执行,这个就不是写者优先了,而是读者写者公平竞争。

(3)写者优先2。

为了保证写者相对于读者的优先,需要提高写者进程的优先级。这里除增加一个排队信号量read,让读者和写者在读写之前都在此信号量上排队。还需增加一个信号量write_first,来保证写者优先。写者优先2的程序设计如下:
int rc, wc = 0; //用于读者,写者的计数
semaphore read, write = 1;                      //用于读进程和写进程的互斥信号量
semaphore rc_mutex, wc_mutex, write_first = 1;//用于读时、写时和写者优先的互斥
          void reader(){    
while(1){
         P(write_first);                                         //用来保证写者优先。若有写进程,第二个后的读者等待在这
        P(read);                                            //若有写进程,第一个读进程等待; 若无写进程,读进程进入
P(rc_mutex);                                          //开始对rc共享变量进行互斥访问
                   rc++;                                          //更新读进程数
                  if (rc==1) P(write);                        //第一个读进程需要判断是否有写进程在临界区,若有,读进程
//等待,若无,阻塞写进程
V(rc_mutex);                                        //结束对rc共享变量的互斥访问
V(read);                                           //从 read队列中唤醒一个进程
V(write_first);
                  doReading();
P(rc_mutex);                                          //开始对rc共享变量进行互斥访问
rc--;                                           //更新读进程数量
if (rc==0) V(write);                           //最后一个离开临界区的读进程需要判断是否有写进程
                        //需要进入临界区,若有,唤醒一个写进程进临界区
V(rc_mutex);                                             //结束对rc共享变量的互斥访问
            }
}
  
void writer(){         
while(1){
   P(wc_mutex);                                      //开始对wc共享变量进行互斥访问
      wc++;                                          //更新写进程数
      if (wc==1)  P(read);                                 //第一个写进程需要判断是否有读进程在临界区,若有,写进程   
//阻塞,若无,阻塞新的读进程
   V(wc_mutex);                                        //结束对wc共享变量的互斥访问
   P(write);                                          //限制同一时刻只能有一个写进程进行写操作
       do writing();
V(write);                                                  //结束对写操作的限制
   P(wc_mutex);                                        //开始对wc的互斥访问
       wc--;                                          //更新写进程数量
       if (wc==0)  V(read);                           //最后一个离开临界区的写进程需要判断是否有读进程需要
//进入,若有,唤醒一个读进程进入临界区
V(wc_mutex);                                      //结束对wc的互斥访问
    }
}
    这里write_first的设立是为了保证写者优先。因为write_first的初值是1,在读进程,执行完P(write_first)后等在P(read)这一句的读者最多只有1个。
对于read信号量,每个读进程最开始都要申请一次,之后在真正做读操作前即让出,这使得写进程可以随时申请到 read。而写进程,只有第一个写进程需要申请 read,之后就一直占着不放了,直到所有写进程都完成后才让出。等于只要有写进程提出申请就禁止读进程在read信号量上排队。
假设一个写进程正在写时,接着后续有n个读者正在等待,这时又有一个新的写者要写,比较一下写者优先1和写者优先2的情况:写者优先1新来的写者需要等待n+1次V(read)操作,而写者优先2新来的写者只需等待2次V(read)操作,变相提高了写进程的优先级。


转自点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值