文章目录
互斥操作:在临界区前后分别PV
同步操作:前V后P
1. 生产者消费者问题
(1)问题描述
- 系统中有
一组生产者进程
和一组消费者进程
,生产者进程每次生产一个
产品放入缓冲区,消费者进程每次从缓冲区中取出一个
产品并使用。(注: 这里的“产品”理解为某种数据) - 生产者、消费者
共享
一个初始为空、大小为n的缓冲区
- 只有缓冲区
没满
时,生产者才能把产品放入缓冲区,否则必须等待 - 只有缓冲区
不空
时,消费者才能从中取出产品,否则必须等待 - 缓冲区是临界资源,各进程必须
互斥
地访问
(2)问题分析
-
① 关系分析:生产者和消费者对缓冲区互斥访问是
互斥关系
,同时生产者和消费者又是一个相互协作的关系,只有生产者生产之后,消费者才能消费,它们也是同步关系
-
② 整理思路:
根据各进程的操作流程确定P、V操作的大致顺序
生产者每次要消耗(P)一个空闲缓冲区,并生产(V)一个产品
消费者每次要消耗(P)一个产品,并释放一个空闲缓冲区(V)
往缓冲区放入/取走产品需要互斥 -
③ 信号量设置:
semaphore mutex = 1; //互斥信号量,实现对缓冲区的互斥访问 semaphore empty = n; //同步信号量,表示空闲缓冲区的数量 semaphore full = 0; //同步信号量,表示产品的数量
(3)具体实现
- 实现同步操作时,需要注意“前V后P”
- 实现互斥的P操作一定要放在同步的P操作之后
2. 多生产者-多消费者问题
(1)问题描述
- 桌子上有一只盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等着吃盘子中的橘子,女儿专等着吃盘子中的苹果。只有盘子空时,爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出水果。
(2)问题分析
- ① 关系分析:
- 互斥关系:对缓冲区(盘子)的访问要
互斥
地进行 - 同步关系:
- 父亲将苹果放入盘子后,女儿才能取苹果
- 母亲将橘子放入盘子后,儿子才能取橘子
- 只有
盘子为空
时,父亲或母亲
才能放入水果
- 互斥关系:对缓冲区(盘子)的访问要
- ② 信号量设置:
semaphore mutex = 1; //实现互斥访问盘子 semaphore apple = 0; //盘子中有几个苹果 semaphore orange = 0; //盘子中有几个橘子 semaphore plate = 1; //盘子中还可以放多少个水果
(3)具体实现
- 在生产者-消费者问题中,如果
缓冲区为1
,那么有可能不需要设置互斥信号量就可以实现互斥访问缓冲区,但要具体情况具体分析
3. 吸烟者问题
(1)问题描述
- 假设一个系统有
三个抽烟者进程
和一个供应者进程
。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了
,供应者就会放另外两种材料在桌上,这个过程一直重复(让三个抽烟者轮流地抽烟
)。
(2)问题分析
- ① 关系分析:
- 桌子可以抽象为容量为1的缓冲区,材料可以两两看做一种组合
- 同步关系:
- 桌子上有组合一 ,第一个抽烟者取走东西
- 桌子上有组合二 ,第二个抽烟者取走东西
- 桌子上有组合三 ,第三个抽烟者取走东西
- 发出完成信号,供应者将下一个组合放到桌上
- ② 信号量设置:
semaphore offer1 = 0; //桌上组合一的数量 semaphore offer2 = 0; //桌上组合二的数量 semaphore offer3 = 0; //桌上组合三的数量 semaphore finish = 0; //抽烟是否完成 int i = 0; //实现轮流操作
(3)具体实现
- 供应者
- 吸烟者
4. 读者写者
(1)问题描述
- 有读者和写者两组并发进程,共享
一个文件
,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者
可以同时对文件执行读操作
;②只允许一个写者
往文件中写信息
;③任一写者在完成写操作之前不允许
其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出。
(2)问题分析
- ① 关系分析:
- 两类进程:写进程、读进程
- 互斥关系:写进程-写进程、写进程-读进程(读进程之间不存在互斥问题)
- ② 信号量设置:
semaphore rw = 1; //实现对共享文件的互斥访问 int count = 0; //记录当前有几个读进程在访问文件 semaphore mutex = 1; //用于保证对count变量的互斥
(3)具体实现
-
写进程
-
读进程
-
该算法有潜在问题:只要有读进程还在读,写进程就要一直阻塞等待,可能“饿死”,因此该算法读进程优先。
-
解决方法:再增加一个信号量
semaphore w = 1;
用于实现“写优先” -
写进程
-
读进程
-
该算法是相对公平的先来服务原则
5. 哲学家进餐
(1)问题描述
- 一张圆桌上坐着5名哲学家,每两个哲学家直接的桌子上摆着一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
(2)问题分析
- ① 关系分析:系统中有5个哲学家进程,5位哲学家与左右邻居对其中间筷子的访问是互斥关系。
- ② 整理思路:这个问题中只有互斥关系,但与之前遇到的问题不同的是,每个哲学家进程需要同时持有两个临界资源才能开始吃饭。如何
避免
临界资源分配不当造成的死锁现象
,是哲学家问题的精髓。 - ③ 信号量设置:定义互斥信号量数组
chopstick[5]={1,1,1,1,1};
用于实现对5个筷子的互斥访问。并对哲学家按0~4编号,哲学家i左边的筷子编号为i,右边的筷子编号为(i+1)%5。