文章目录
- 1. 生产者-消费者问题
- 2. 吸烟者问题
- 3. 读者-写者问题
- 4. 哲学家进餐问题
1. 生产者-消费者问题
问题模型:
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用(产品:某种数据)。
生产者、消费者共享一个初始为空、大小为 n 的缓冲区。
- 只有缓冲区没满时,生产者才能把产品放进去,否则必须等待(同步关系)。
- 只有缓冲区不空时,消费者才能取出产品,否则必须等待(同步关系)。
- 缓冲区必须是互斥访问的,是临界资源(互斥关系)。
要注意各种 P 操作的先后顺序(因为P操作会让进程阻塞),否则容易出现“死锁”现象。
- 在这个问题模型中,要注意的是同步要在互斥前边。
多生产者 - 多消费者
2. 吸烟者问题
问题模型:
生产者可以往桌子上放不同的材料,三个吸烟者需要拿到自己对应的材料,才可以完成吸烟动作。吸烟完成后,通知生产者,生产者才放下一个材料,三个吸烟者轮流吸烟。
主要的同步、互斥关系:
- 桌子是一个容量为 1 的缓冲区,要互斥访问。(互斥关系)
- 桌子上有组合一,第一个人才可以抽烟。(同步关系)
- 桌子上有组合二,第二个人才可以抽烟。(同步关系)
- 桌子上有组合三,第三个人才可以抽烟。(同步关系)
- 每个吸烟者吸烟结束,供应者才可以将下一个组合放在桌子上。(同步关系)
注意这里边,互斥的关系,并没有单独设置一个信号量,因为4个负责同步的信号量,同一时刻只会有一个有值。 - 吸烟者问题为解决“可以生产多个产品的单生产者”问题提供了一个思路。
3. 读者-写者问题
问题模型:
- 多个读进程可以同时读,不会出问题。
- 读写进程一起访问共享文件的话,会导致读进程读的并不是自己想要的那份(被写进程改了)
- 多个写进程一起写入共享文件,可能导致数据被覆盖。
综上:
- 只可以多个读进程一起。
- 写进程执行的时候,其他的写进程和读进程都不能访问。
- 读进程执行的时候,写进程不能访问。
关系如下:
- 写 - 写(互斥)
- 读 - 写(互斥)
读写者模式的精巧之处:
上边图里对读进程的设计中,如果没有count变量记录读进程的数量的话,会导致读进程与读进程之间也是互斥的,这并不是我们希望的。如果像上图中的设计,当多个读进程去读共享文件时(有先后顺序),只有访问共享文件的进程才会上锁,其他的读进程都不会进行上锁操作,因为通过count变量可以知道已经有读进程在读了,此时去读的话,并不会和写进程冲突,可以放心的读。同理,只有最后一个读完文件的读进程才会执行解锁操作,因为比它先读完的那些进程不能执行解锁操作,一旦解锁,写进程就会开始写入,就会造成读写冲突。
上边的这种设计存在一个问题,如上图的左下角所示,如果两个读进程并发的执行在读count变量时,都为0,会导致其中一个上锁,另一个读进程被阻塞,这是不可以的。所以再对count变量进行互斥访问,加一个mutex。
可见,上边这种方式是“读进程优先”的,只要有读进程在读,那写进程就会一直被阻塞,可能“饿死”。
再加入一个信号量 w,把写进程的优先级提一提。
引入 信号量w以后,并发执行的情况。
-
读者1->读者2
读者1读完以后,会对mutex和w都执行V操作,所以读者2可以正常读文件。
-
写者1->写者2
多了一个互斥信号量,所以也不会有影响。
*写者1->读者1
写者1执行后,w和rw上锁,此时如果有读者进程尝试访问,w信号量会让该读进程阻塞。
-
读者1->写者1->读者2
读者1在读的时候,写者1尝试访问,读者1会被w阻塞,当读者1执行了 V(w) 以后,写者1会对w上锁,然后被rw阻塞,如果此时,读者2尝试访问,因为写者1对w上了锁,所以读者2会被w阻塞掉。等到读者1执行了V(rw)以后(此时count一定为1,因为读者2被阻塞着),写者1可以对rw上锁,开始正常的写入。等待写者1操作结束,对rw和w解锁后,读者2就可以正常的进行了。
这就避免了之前,写进程饥饿的问题。
-
写者1->读者1->写者2
写者1对w和rw上锁后,开始写文件操作,此时读者1尝试访问,被w信号量阻塞,此时再有写者2尝试访问,也被w信号量阻塞,当写者1完成任务,释放rw和w后,因为读者1先于写者2上锁排队,所以w信号量被解锁后,读者1开始执行,写者2依然开始被阻塞着。
这种方法相对读者和写者都相对公平。牛逼!
总结:
- count服务于读进程,保证读进程不互斥,mutex用于保证对count的互斥访问。
- w用于解决写进程饥饿。
4. 哲学家进餐问题
问题模型:
- 下面这种方案是不合理的,会存在死锁现象,所有的哲学家都等待自己右手边的筷子,又没有人放下自己手中的筷子。
两个解决死锁问题的思路:
- 限制最多只允许4个哲学家进餐。
- 要求奇数号的哲学家先拿左手边筷子,偶数号哲学家先拿右手边筷子。
- 要求有人拿筷子的时候,其他人不能拿。(有书上说的是,当左右筷子都可用时才允许拿起来)
第三种方法:
情况说明:
- 0号想吃饭,拿起左边筷子时,此时进程切换,2号想吃饭了,2号被mutex阻塞,只能等到0号吃完,2号采可以拿筷子、吃饭。
- 0号拿起左右筷子,对mutex解锁后,0号开始吃饭,1号此时只能拿起左筷子,拿右筷子时被阻塞,如果此时2号也想吃饭,但它一根筷子也拿不了(即使左右都有筷子可用),因为被mutex阻塞了。只能等1号吃完,它再吃。
- 0号拿起左右筷子,对mutex解锁后,0号开始吃饭,4号想吃饭,只能拿起左侧的筷子,拿右筷子时被阻塞
哲学家进餐问题的关键在于解决进程死锁
哲学家进餐问题的关键在于解决进程死锁
哲学家进餐问题的关键在于解决进程死锁