其他分享
首页 > 其他分享> > 操作系统 经典互斥与同步问题

操作系统 经典互斥与同步问题

作者:互联网

生产者-消费者问题

在这里插入图片描述
在这里插入图片描述

问题分析

①生产者—消费者之间的同步关系表现为:一旦缓冲池中所有缓冲区均装满产品时,生产者必须等待消费者提供空缓冲区;一旦缓冲池中所有缓冲区全为空时,消费者必须等待生产者提供满缓冲区。

②生产者—消费者之间还有互斥关系:由于缓冲池是临界资源,所以任何进程在对缓冲区进行存取操作时都必须和其他进程互斥进行。

生产者-消费者问题是相互合作进程关系的一种抽象

问题解答

①所用信号量设置如下:
Ⅰ)同步信号量empty,初值为n,表示消费者已把缓冲池中全部产品取走,有n个空缓冲区可用。
Ⅱ)同步信号量full,初值为0,表示生产者尚未把产品放入缓冲池,有0个满缓冲区可用。
Ⅲ)互斥信号量mutex,初值为1,以保证同时只有一个进程能够进入临界区,访问缓冲池。

用信号量机制解决生产者—消费者问题

在这里插入图片描述

在生产者—消费者问题中要注意以下几点

item B[n];       	//数组B用来模拟n个缓冲区Semaphore mutex,empty,full;mutex.value=1,empty.value=n,full.value=0;int in=0;         	//in指针指向一个空缓冲区int out=0;           //out指针指向一个满缓冲区item product;     	//product代表一个产品cobegin
  process Producer_i()           	//i=1,2,3,…,m
  {
    while(1)
    {  
        product=produce();	//生产一个产品
        P(empty);          	//请求空缓冲区
        P(mutex);          	//请求独占缓冲池
        B[in]=product;     //产品放到空缓冲区
        in=(in+1)%n;    //in移至下一个空缓冲区
        V(mutex);          //释放缓冲池的使用权
        V(full);    //满缓冲区个数增一,若有阻塞的消费者进程则唤醒之
     }   
   }
   process Consumer_j()         //j=1,2,3,…,k        
	{
    	while(1){
          P(full);            //请求消费满缓冲区中的产品
          P(mutex);           //请求独占缓冲池使用权
          product=B[out];  //从满缓冲区中取出产品
          out=(out+1)%n; //out移至下一个满缓冲区
          V(mutex);           //释放对缓冲池的使用权
          V(empty);           //空缓冲区个数增一
          //若有阻塞的生产者进程则唤醒之
          consume();          	//进行产品消费
        }
  	}   coend

哲学家进餐问题

问题描述:5个哲学家同坐在

一张圆桌旁,每个人的面前摆
放着一碗面条,碗的两旁各摆
放着一只筷子。假设哲学家的
生活除了吃饭就是思考问题(这是一种抽象,
即对该问题而言其他活动都无关紧要),而吃饭的时候需要左手拿一只筷子
右手拿一只筷子,然后开始进餐。
吃完后又将筷子放回原处,继续思考问题。

一个哲学家的活动进程可表示为

(1)思考问题;
(2)饿了停止思考,左手拿一只筷子(如果左侧哲学家已持有它,则需要等待);
(3)右手拿一只筷子(如果右侧哲学家已持有它,则需要等待);
(4)进餐;
(5)放右手筷子;
(6)放左手筷子;
(7)重新回到思考问题状态(1)

如何协调5个哲学家的活动进程

利用信号量解决哲学家进餐问题

可采取以下几种解决方法

//可预防死锁Semaphore mutex, chopstick[5];mutex.value=4;for(int i=0;i<5;i++)   chopstick[i].value=1;cobegin
    process Philosopher_i( ) // i=0, 1, 2, 3, 4
    {    while(1)
        { 
            think();                //思考
            P(mutex);     //最多允许4个哲学家申请筷子
            P(chopstick[i]);        //拿起左手的筷子
            P(chopstick[(i+1)%5]);  //拿起右手的筷子
            V(mutex);       //已拿到两个筷子,解除申请
            eat( );                  //进餐
            V(chopstick[i]);        //放回左手的筷子
            V(chopstick[(i+1)%5]);  //放回右手的筷子
        }    
    }coend

Semaphore chopstick[5];for(int i=0;i<5;i++)   chopstick[i].value=1;cobegin
  process Philosopher_i()  // i=0, 1, 2, 3, 4
  {
      while(1)
      {   
          think();           //思考
          SP(chopstick[i],chopstick[(i+1)%5]); 
          //同时拿起左、右手的两只筷子
          eat();                               //进餐
          SV(chopstick[i],chopstick[(i+1)%5]); 
          //同时放回左、右手的两只筷子
      }
  }   coend

//可预防死锁Semaphore chopstick[5];for(int i=0;i<5;i++)   chopstick[i].value=1;cobegin
  process Philosopher_i()     // i=0, 1, 2, 3, 4
  {   
      while(1)
      {
          think();//思考
          if(i%2==1){//如果是奇数号哲学家  
            P(chopstick[i]);      //拿起左手的筷子
            P(chopstick[(i+1)%5]);   //拿起右手的筷子
          }  else{  //如果是非奇数号哲学家
            (chopstick[(i+1)%5]); //拿起右手的筷子
            P(chopstick[i]);     //拿起左手的筷子
          }
          eat( );                         //进餐
          V(chopstick[i]);                 //放回左手的筷子
          V(chopstick[(i+1)%5]);           //放回右手的筷子
      }
  }    coend

读者—写者问题

读者-写者问题中的进程之间存在3种制约关系

解决

睡眠理发师问题

问题描述:有一个理发师、一把理发椅和n把供等侯理发顾客坐的椅子。
如果没有顾客则理发师就在理发椅子上睡觉。
当一个顾客到来时则必须唤醒理发师进行理发。
若理发师正在理发时又有顾客到来,
如果有空椅子可坐则该顾客就坐下来等侯,
如果没有空椅子可坐就离开理发厅。

解决

Semaphore wakeup,wait,mutex;wakeup.value=0,wait.value=0,mutex.value=1;int rc=0;cobegin
  process Customer_i()  //i=1, 2, 3, …, m
  { 
      P(mutex);
      rc++;                   //等待理发顾客人数加1
      if(rc==1)
      { 
          坐在理发椅上;
          V(wakeup); //第一个顾客到来唤醒理发师
          V(mutex);
          P(wait);   //阻塞自己等待理发师唤醒
      }
      else if(rc>n+1)    //顾客已无椅子可坐 
      { 
          rc--;      //该顾客需离开理发厅
          V(mutex);
      }
      else     //顾客不是第一个到达但有空椅子可坐
      { 
          坐在空椅子上;
          V(mutex);
          P(wait);     //阻塞自己等待理发师唤醒
      }
      离开理发厅;   
  }
  process Barber()
  {
      P(wakeup); //无理发的顾客则理发师睡眠
      while(1)
      {
          P(mutex);
          if(rc!=0)            //有等待理发的顾客
          {
              V(wait);  //唤醒wait队列上第一个顾客
              让被唤醒的顾客坐在理发椅上理发;
              rc--;               //等待理发顾客人数减1
              V(mutex);
          }
          else
          {  
              V(mutex);
              P(wakeup);  //无理发顾客则理发师睡眠
          }
      }
  }coend

缓冲区数据传送问题

设有进程A、B和C,分别调用函数get、copy和put
对缓冲区S和T进行操作。
其中,get负责把数据块输入到缓冲区S中,copy负责从
缓冲区S中取出数据块并复制到缓冲区T中,
put负责从缓冲区T中取出数据输出打印,
试描述进程A、B和C的实现算法。

在这里插入图片描述

Semaphore empty1,empty2,full1,full2;empty1.value=1,empty2.value=1;full1.value=0,full2.value=0;cobegin
  process A()
  { 
      while(1)
      { 
          P(empty1);    //测试缓冲区S是否非空
          //非空则阻塞进程A
          get();        	//将数据块输入到缓冲区S
          V(full1); 	//通知进程B可取出S中数据块
          //若进程B阻塞则唤醒它
      }
  }
  process B()
  {   
      while(1)
      {  
          P(full1);    //S是否有数据,无则阻塞进程B
          P(empty2);    //测试缓冲区T是否非空
          //非空则阻塞进程B
          copy();      //从S中取出数据复制到缓冲区T
          V(empty1);   //通知进程A缓冲区S为空
          //若进程A阻塞则唤醒它
          V(full2); //通知C可取出缓冲区T中数据打印
          //若进程C阻塞则唤醒它
      }
  }
  process C()
  {
      while(1)
      {
          P(full2);    //T是否有数据,无则阻塞进程C
          put();         	//取出缓冲区T中数据打印
          V(empty2);  	//通知进程B缓冲区T为空
          //如进程B阻塞则唤醒它
      }
  }coend

汽车过桥问题

问题描述:桥上不允许两车交会,但允许同方向多辆车依次通行
(即桥上可以有多个同方向的车)。
用P、V操作实现交通管理以防止桥上堵车。

解决方法:

Semaphore mutex1,mutex2,wait;mutex1.value=1,mutex2.value=1,wait.value=1;int count1=0,count2=0;cobegin
  process N_i()       	//i=1,2,3,…,m
  {  
      P(wait); //对方车辆过桥时阻止本方车辆上桥
      P(mutex1);  //申请对count1的访问权
      //如果对方车辆已上桥则阻塞自己
      if(count1==0) P(mutex2);  //己方第一个上桥车辆则阻塞对方车辆上桥
      count1++;            //己方过桥车辆加1
      V(mutex1);          //释放对count1的访问权
      V(wait);                //允许后续车辆申请过桥;
      P(mutex1);          //申请对count1的访问权
      count1--;              //己方过桥车辆减1
      if(count1==0) V(mutex2); 
      //己方最后一个车辆过桥后允许对方车辆上桥
      //如有被阻塞的对方车辆则唤醒其过桥
      V(mutex1);         //释放对count1的访问权    
  }
  process S_j()           	//j=1,2,3,…,n
  {  
      P(wait); //对方车辆申请过桥时阻止本方车辆上桥
      P(mutex2);    //申请对count2的访问权
      //如果对方车辆已上桥则阻塞自己
      if(count2==0) P(mutex1);	
      //己方第一个上桥车辆则阻塞对方车辆上桥
      count2++;           //己方过桥车辆加1
      V(mutex2);         //释放对count2的访问权
      V(wait);       //允许后续到达的车辆请求过桥;
      P(mutex2);         //申请对count2的访问权
      count2--;             //己方过桥车辆减1
      if(count2==0) V(mutex1);
      //己方最后一个车辆过桥后允许对方车辆上桥
      //如有被阻塞的对方车辆则唤醒其过桥
      V(mutex2);         //释放对count2的访问权
  }coend

实例总结

实现进程的同步互斥实际就是给进程的并发执行增加一定的限制,以保证被访问的共享数据的完整性和进程执行结果的可再现性。

标签:同步,操作系统,互斥,mutex,缓冲区,筷子,进程,顾客
来源: https://blog.51cto.com/u_14175378/2759913