前言
解决同步互斥问题的思路,源于对王道讲解的总结笔记。
同类型题目:
【考研】操作系统:2019年真题43(同步互斥问题)_住在阳光的心里的博客-CSDN博客
【考研】操作系统:2015年真题45(同步互斥问题)_住在阳光的心里的博客-CSDN博客
【考研】操作系统:2014年真题47(同步互斥问题)_住在阳光的心里的博客-CSDN博客
一、思路
解决同步互斥问题,思路步骤:
1. 分析各进程之间的同步互斥关系;
2. 设置互斥信号量 mutex = 1、同步信号量(一般设可使用的资源数为empty = N)。
3. 最好画出同步互斥关系图,并判断属于哪一种类型,如生产者-消费者问题、读者-写者问题、哲学家进餐问题、吸烟者问题。
针对生产者-消费者问题、读者-写者问题、哲学家进餐问题、吸烟者问题,这些经典同步问题可以参考:
计算机操作系统——经典同步问题_御承扬的博客-CSDN博客
二、题目
45. (7分)三个进程P1、P2、P3互斥使用一个包含N(N > 0)个单元的缓冲区。
P1 每次用 produce()生成一个正整数并用 put()送入缓冲区某一空单元中;
P2 每次用 getodd()从该缓冲区中取出一个奇数并用 countodd()统计奇数个数;
P3 每次用 geteven()从该缓冲区中取出一个偶数并用 counteven()统计偶数个数。
请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义的信号量的含义。要求用伪代码描述。
解:
(1)互斥资源:
P1、P2与P3互斥使用缓冲区,所以设置互斥信号量 mutex
(2)同步问题:
P1、P2 因为奇数的放置与取用而同步,设同步信号量 odd;
P1、P3 因为偶数的放置与取用而同步,设同步信号量 even;
P1、P2、P3 因为共享缓冲区,设同步信号量 empty,初值为 N。
(3)三个进程P1、P2、P3同步互斥关系图如下:
(属于吸烟者问题:一个生产者生产多种商品,多个消费者取走各自产品。即 P1 生产奇数和偶数,P2 和 P3 取走各自需要的数)
(4)伪代码如下:
semaphore mutex = 1; // 设置互斥信号量,互斥访问缓冲区
semaphore odd = 0; // 有几个奇数
semaphore even = 0; // 有几个偶数
semaphore empty = N; // 空缓冲区的数量
P1(){ // 生产者while(1){x = produce(); // 生成一个数P(empty); //消耗空缓冲区的数量P(mutex); //缓冲区是否被占用put();V(mutex); //释放缓冲区if(x % 2 == 0) // 此处判断奇偶数是重点V(even); // 产偶数,向 P3 发出信号elseV(odd); // 产奇数,向 P2 发出信号}}
P2(){ // 取奇数while(1){ // 也可用while(true)P(odd); // 收到 P1 发来的信号,,已产生一个奇数,则 P2 消耗一个奇数P(mutex); // 缓冲区是否被占用getodd();V(mutex); // 释放缓冲区V(empty); // 向 P1 发信号,多出一个空单元countodd(); }
}
P3(){ // 取偶数while(1){P(even); // 收到 P1 发的信号,已产生一个偶数,则 P3 消耗一个偶数P(mutex); // 缓冲区是否被占用geteven();V(mutex); // 释放缓冲区V(empty); // 向 P1 发信号,多出一个空单元counteven();}
}
完整答案写法:
semaphore mutex = 1; // 设置互斥信号量,互斥访问缓冲区
semaphore odd = 0; // 有几个奇数
semaphore even = 0; // 有几个偶数
semaphore empty = N; // 空缓冲区的数量main()
cobegin{Process P1() while(1){ x = produce(); // 生成一个数P(empty); //消耗空缓冲区的数量P(mutex); //缓冲区是否被占用put();V(mutex); //释放缓冲区if(x % 2 == 0) V(even); // 产偶数,向 P3 发出信号elseV(odd); // 产奇数,向 P2 发出信号}Process P2() // 取奇数while(1){P(odd); // 收到 P1 发来的信号,,已产生一个奇数,则 P2 消耗一个奇数P(mutex); // 缓冲区是否被占用getodd();V(mutex); // 释放缓冲区V(empty); // 向 P1 发信号,多出一个空单元countodd(); }Process P3() // 取偶数while(1){P(even); // 收到 P1 发的信号,已产生一个偶数,则 P3 消耗一个偶数P(mutex); // 缓冲区是否被占用geteven();V(mutex); // 释放缓冲区V(empty); // 向 P1 发信号,多出一个空单元counteven();}}coend