进程推进的合理有序同步——信号量
等待是进程同步的核心
信号量的出现是对于如果有多个P的时候,只有信号是不能唤醒所有生产者的,只能唤醒一个生产者。
- 信号只能唤醒一个生产者
信号量小于0对应的是有多少个进程睡眠了
- 要学会等待(观察信号量是否为负,如果是负数就需要等待)
停是很重要的
- 用临界区来保护信号量
- 用信号量来支持进程的同步
信号量(整型变量)
互斥
让进程之间的合作变得合理有序
实现这个的依据是信号量
想象一个司机和售票员的例子,司机要启动车辆,这个时候应该让售票员先关门,然后发一个信号,然后司机可以启动车辆,我们说司机是在等待一个信号。
同理,司机停车了,就需要发送一个信号给售票员,然后售票员才能开门。

等待就是阻塞,这个也是进程同步的核心。
比如说生产者--消费者模型,当缓冲区满的时候,就要停下来,不然会溢出。如果缓冲区空了,就不敢再消费了,已经没有东西可以消费了。

引出信号量
之前的信号在程序里面的体现是counter,信号表示的只是有或无,它只能唤醒一个进程,然后就无效了,如果有n个进程,那么剩下的n - 1个进程就会一直sleep下去。所以我们需要一个量——信号量来表示有多少个进程在睡眠,唤醒的时候需要唤醒多少个进程。
信号量——记录有多少个进程睡眠了
如果只有信号的话,只能是
发信号还有等信号,对应的是唤醒和睡眠。

如果有了信号量的话,我们用
sem来表示,根据sem是多少来决定是唤醒还是睡眠,如果sem已经小于0了,那就睡眠,然后消费者进程看到sem小于0了,就会去唤醒。这样子就实现了
进程的走走停停


习题

P操作和V操作
- P操作对应的是消费者
- V操作对应的是生产者
睡眠和唤醒对应的是都是信号量是否会小于0
P和V的2段代码

生产者在共享缓冲区的时候,消费者不能进去
消费者在共享缓冲区的时候,生产者不能进去实现这一点是需要靠
互斥信号量来实现
为什么要保护信号量
因为多个进程会共同修改信号量,这样会导致信号量的语义错误。这种错误就称为——
和
调度有关的共享数据语义错误
什么是临界区?
假如A进程有段代码,B进程有段代码,他们俩都有一个小部分的代码涉及到了相同的信号量,那么这一小部分就是临界区,临界区的执行是一个原子操作——一个进程进去后修改完才能解锁。
临界区是成对or成组出现的
互斥——不能同时进入
死锁预防就是2个方法
- 一次性申请所有资源
- 按序等待
死锁避免
找到一个
安全序列(通过银行家算法)
图片.png
死锁避免的代价太大了
因为每一个进程
Pi每次申请的时候,都要进行一次银行家算法,看是否会引起死锁,时间复杂度太高
图片.png
图片.png
死锁检测和恢复
发现问题,检测到问题用的还是银行家算法,不过执行的次数少了一些了。
恢复的时候采用的是进程回滚,回滚到一定程度了看看是否还会死锁。
但是选择谁回滚,和实现回滚都比较麻烦。

死锁忽略的方法


死锁
多个进程由于
互相等待对方持有的资源,从而导致任何一个进程都无法执行的情况。
死锁的成因
- 互斥——一个资源被A进程占用后,其他进程无法使用
- A进程占有了资源后,不释放,
还要去申请其他的资源
好比已经占有了一条路,还要继续前进到
其他的道路
- 环路等待——每个进程占有的资源和想要申请的资源形成了一个环路
相当于每辆公交车已经有了自己的车道,还想要去占别人的车道,但是别人不让,所以就
僵持住了。
死锁的4个必要条件
- 互斥使用
- 不可抢占——资源只能进程自己放弃,比如
公交车自己开走
上面2点都是资源的固有属性
- 请求和保持——进程已经有了一个资源还不释放,同时去申请其他的资源
-
循环等待
图片.png



