前言
解决同步互斥问题的思路,源于对王道讲解的总结笔记。
同类型题目:
【考研】操作系统:2019年真题43(同步互斥问题)_住在阳光的心里的博客-CSDN博客
【考研】操作系统:2015年真题45(同步互斥问题)_住在阳光的心里的博客-CSDN博客
【考研】操作系统:2014年真题47(同步互斥问题)_住在阳光的心里的博客-CSDN博客
一、思路
解决同步互斥问题,思路步骤:
1. 分析各进程之间的同步互斥关系;
2. 设置互斥信号量 mutex = 1、同步信号量(一般设可使用的资源数为empty = N)。
3. 最好画出同步互斥关系图,并判断属于哪一种类型,如生产者-消费者问题、读者-写者问题、哲学家进餐问题、吸烟者问题。
针对生产者-消费者问题、读者-写者问题、哲学家进餐问题、吸烟者问题,这些经典同步问题可以参考:
二、题目
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 发出信号
else
V(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 发出信号
else
V(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