进程经典问题总结

Posted by1314

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程经典问题总结相关的知识,希望对你有一定的参考价值。

以下出现代码均为伪代码;

2.5.1 生产者-消费者问题(考试模型占比 60%)

技术图片
分析上图:缓冲区存在互斥问题,生产者与消费者之间还 存在同步问题

1. 利用记录型信号量解决生产者-消费者问题(背下来)

??假定在生产者和消费者之间的共用缓冲池中具有n个缓冲区,这时可以利用互斥信号量mutex(初始值 1 )实现进程对缓冲池的互斥作用;利用信号量empty(初始值为n)和full(初始值为0)分别表示缓冲池中空缓冲区和满缓冲区的数量。
??又假定这些生产者和消费者相互等效,置业总缓冲区未满,生产者便可将消息送入缓冲池中,只要缓冲池没空,消费者便可从缓冲池中取走一个消息

semaphore mutex =1; //缓冲区互斥操作的互斥信号量
semaphore empty = n; //空缓冲区数目,类型为资源信号量
semaphore full = 0; //满缓冲区为数目,类型为资源信号量
item buffer[n] 
int in =0,out =0;
producer() //生产者进程
{
      while(1)
      {
            produce an item nextp;
            P(empty); //empty - 1,资源信号量又有同步作用
            P(mutex); //加锁————>当多个生产者的时候要互斥访问
            buffer[in] = nextp;
            in = (in+1)%n; //循环队列
            V(mutex); //解锁
            V(full);  //full + 1
      }
}
consumer() //消费者进程
{
      while(1)
      {
            P(full); //full - 1
            P(mutex); //加锁————>当多个消费者的时候要互斥访问
            nextc = buffer[out];
            out = (out+1)%n; //循环队列
            V(mutex); //解锁
            V(empty);  //full + 1
            consumer the item in nextc;
      }
}

注:
(1)empty + full = n ;
(2)若多个P操作颠倒,可能会存在死锁问题。


2.利用AND信号量解决生产者-消费者问题 (了解就行)

对于生产者-消费者问题,也可以利用AND信号量来解决,即:

  • 用Swait(empty,mutex)来代替wait(empty)和wait(mutex)
  • 用Ssignal(mutex,full)来代替signal(mutex)和signal(full)
  • 用Swait(full,mutex)来代替wait(full)和wait(mutex)
  • 用Ssignal(mutex,empty)来代替signal(mutex)和signal(empty)
semaphore mutex =1; //缓冲区互斥操作的互斥信号量
semaphore empty = n; //空缓冲区数目,类型为资源信号量
semaphore full = 0; //满缓冲区为数目,类型为资源信号量
item buffer[n] 
int in =0,out =0;
producer() //生产者进程
{
      while(1)
      {
            produce an item nextp;
            Swait(empty,mutex)
            buffer[in] = nextp;
            in = (in+1)%n; //循环队列
            Ssignal(empty,mutex); //解锁
      }
}
consumer() //消费者进程
{
      while(1)
      {
            Swait(full,mutex)
            nextc = buffer[out];
            out = (out+1)%n; //循环队列
            Ssignal(empty,mutex)
            consumer the item in nextc;
      }
}

3. 利用管程来解决生产者-消费者问题(自主命题

建立一个管程,并命名为producerconsumer,或简称PC。其中包括两个过程:
(1)put(x)过程。生产者利用该过程将自己生产的产品放到缓冲池中,并用整型变量count来表示在缓冲池中已有的产品数目,当count >= n 时,表示缓冲池已满,生产者等待。(也就意味需要有2个条件变量
(2)get(x)过程。消费者利用该过程从缓冲池中取出一个产品,当count <= 0 时,表示缓冲池中已经无可取用的产品,消费者等待。


对于条件变量notfull 和 notempty,分别有两个过程cwait 和 csignal对它们进行操作:
(1)cwait(condition)过程:当管程被一个进程占用时,其他进程调用该过程时阻塞,并挂在条件condition 的队列上
(2)csignal(condition)过程:唤醒在cwait执行后阻塞在条件 condition 队列上的进程,如果这样的进程不止一个,则选择其中一个实施唤醒操作;如果队列为空,则无操作而返回

monitor producer-consumer //类似于一个类
{
      int in=0,out=0,count=0;
      itm buffer[n];
      condition notfull,notempty;
      void put(item nextp)
      {
            if count >= n then 
                  cwait (notfull)
            buffer [in]=nextp;
            in= (in+1)%n;
            count =count +1;
            csignal(notempty);
      }
      void get(item *x)
      {
            if count <= 0 then 
                  cwait (notempty)
            *x=buffer[out];
            out= (out+1)%n;
            count =count - 1;
            csignal(notfull);  //告诉生产者你可以生产了
      }
}PC;
//利用管程解决生产者-消费者问题
process producer()
{
      item x;
      while (TRUE)
      {
            produce an item in x;
            PC.put(item);  //相当于调用方法
      }
}
process consumer()
{
      item x;
      while (TRUE)
      {
            PC.get(item);
            consumer an item in x;
      }
}

2.5.2 哲学家进餐问题(考试模型占比 10%)

??5个哲学家坐在桌子边,桌上有 5 个碗和 5 只筷子,哲学家的生活方式是交替的进行思考和进餐,哲学家饥饿时便拿起两边的筷子进餐,但只有当拿到两只筷子后才能进餐,用餐完毕放下筷子,继续思考。
小提取:

  • 思考问题
  • 饿了停止思考,左手拿一只筷子(如果左侧哲学家已经持有它,需要等待)
  • 右手拿一只筷子(如果右侧哲学家已经持有它,需要等待)
  • 进餐
  • 放右手筷子
  • 放左手筷子
  • 重新回到思考问题状态


1. 利用记录型信号量解决哲学家进餐问题(没有你先我后的同步问题)

?筷子对应临界资源,在一段时间内只允许一位哲学家使用。为实现筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量构成信号量数组。————> semaphore chopstick[5];

方法一:互斥吃饭

??至多只允许四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并且吃完后,释放两只筷子

semaphore chopstick[5]={1,1,1,1,1};
semaphore eating = 4; //仅允许四个哲学家可以进餐
void philosopher(int i)  // 第 i 位哲学家的活动可以描述为
{
      while( 1 )
      {
            P(eating); //请求就餐,若是第五个则先挨饿
            P(chopstick[i]); //画个圈你就知道,这是他左手边的筷子
            P(chopstick[i+1] % 5);
            eating();  //进餐
            V(chopstick[i+1] % 5);  //释放右边筷子
            V(chopstick[i]); //释放左边
            V(eating);  //释放信号量给其他哲学家
      }
}

方法二:互斥拿筷子的动作

??仅当哲学家的左、右两只筷子均可用的时候,才可以进餐

semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex = 1; //设置取筷子的信号量
void philosopher(int i)  // 第 i 位哲学家的活动可以描述为
{
      while( 1 )
      {
            thinking();
            P(mutex); //在取筷子前获得互斥量
            P(chopstick[i]); //画个圈你就知道,这是他左手边的筷子
            P(chopstick[i+1] % 5);
            V(mutex);  //释放互斥量
            eating();  //进餐
            V(chopstick[i+1] % 5);  //释放右边筷子
            V(chopstick[i]); //释放左边
      }
}

方法三:互斥拿筷子顺序(奇偶数)

??规定奇数号(1,3,5)哲学家先拿起左边筷子,然后再去拿右边筷子,而偶数()2,4哲学家则相反,即五位哲学家先竞争奇数筷子,获得后再去竞争偶数筷子,最后总会由一位哲学家能过获得两只筷子而就餐,下图是哲学家抢奇数筷子图示。
技术图片

semaphore chopstick[5]={1,1,1,1,1};
semaphore mutex = 1; //设置取筷子的信号量
void philosopher(int i)  // 第 i 位哲学家的活动可以描述为
{
      while( 1 )
      {
            thinking();
            if (i%2==0) //偶数哲学家,先右后左
            {
                  P(chopstick[i+1] % 5);
                  P(chopstick[i]);
                  eating();  //进餐
                  V(chopstick[i+1] % 5);  //释放右边筷子
                  V(chopstick[i]);
            }
            else 
            {
                  P(chopstick[i]);
                  P(chopstick[i+1] % 5);
                  eating();  //进餐
                  V(chopstick[i]);
                  V(chopstick[i+1] % 5);  //释放右边筷子
            }
      }
}

2. 利用 AND 信号量机制解决哲学家进餐问题

??要求每个哲学家先获得两个临界资源(筷子)后方能进餐,本质就是AND同步问题,故用 AND 信号量机制解决哲学家进餐问题是最简洁的解法

semaphore chopstick[5]={1,1,1,1,1};
process(i)
{
      while(1)
      {
            think;
            Swait(chopstick[i+1] % 5,chopstick[i]); //把两个筷子全拿起来
            eat;
            Ssignal(chopstick[i+1] % 5,chopstick[i]);      
      }
}

2.5.3 读者 - 写者问题(考试模型占比 30%)

注:读者变形(自主命题

  • 公平队列
  • 写者优先问题

??一个数据文件或记录可被多个进程共享,只要求读该文件的进程称为“Reader 进程”,其他进程为“Writer 进程”,允许多个进程同时读一个共享对象,因为读不会使数据文件混乱,不允许一个Writer 进程和其他Reader 进程或Writer 进程同时访问一个对象。
??读者 - 写者问题:是保证一个Writer 进程必须与其他进程互斥访问共享对象的同步问题。
技术图片

1. 利用记录型信号量解决 读者 - 写者 问题(读者优先)

&emsp:?为实现Reader 和 Writer 进程间在读或写时的互斥而设置了一个互斥信号量 Wmutex.设置一个整型变量 Readcount 表示正在读的进程数目,由于只要一个 Reader 进程在读,便不允许 Writer 进程去写

semaphore rmutex = 1,wmutex = 1; //readcount 和文件的互斥信号量
int readcount=0;
Reader()  //这种方式用于——>独木桥问题
{
      while(1)
      {
            P(rmutex); //允许多个进程同时读一个共享对象
            if (readcount == 0)
                  P(wmutex); //缓冲区互斥
            readcount ++;
            V(rmutex);
            perform read operation;
            P(rmutex);
            readcount --;
            if (readcount == 0)
                  V(wmutex);
            V(rmutex);
      }      
}
Writer()
{
      while(1)
      {
            P(wmutex);
            perform write operation;
            V(wmutex);
      }
}

说个简单问题, 读者 - 写者 问题相当于一个班用自习室抢房间,第一个人来了就开始占房间使用,陆续班上同学进入教室自习,当自习结束且直到最后一个人走了,这个房间不再使用


2. 利用信号量集机制解决 读者 - 写者

??增加一个限制,最多只允许RN个读者同时都。为此引入一个信号量L,并赋予初值为RN,通过执行wait(L,1,1)操作来控制读者数目。每当有一个读者进入时,就要先执行wait(L,1,1)操作,使L的值减 1 。当有 RN 个读者进入后,L便减为 0 ,第 RN+1个读者要进入读时,必然因为wait(L,1,操作失败而堵塞。

int RN = N;
semaphore L = RN,mx = 1;
void Rreder() 
{
      while (TRUE)
      {
            Swait(L,1,1);
            Swait(mx,1,0);  //1,1,0时没有操作,开关;
            perform read operation;
            Ssignal(L,1);
      }
}
void Writer() 
{
      while (TRUE)
      {
            Swait(mx,1,1;L,RN,0);
            perform writer operation;
            Ssignal(mx,1);
      }
}

















以上是关于进程经典问题总结的主要内容,如果未能解决你的问题,请参考以下文章

BootStrap有用代码片段(持续总结)

BootStrap实用代码片段(持续总结)

线程学习知识点总结

几个关于js数组方法reduce的经典片段

几个关于js数组方法reduce的经典片段

多线程面试经典必问题