学习来源:王道考研
1.信号量
1.1信号量机制
信号量:其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量。比如:系统中的一台打印机,就可以设置一个初值为1的信号量。
用一对原语来对信号量进行操作:wait(S)原语和signal(S)原语,简称为P、V操作-------P(S)、V(S)
-
整型信号量
- 用一个整数型的变量作为信号量,来表示系统中某种资源的数量
- 不满足让权等待,会发生忙等,一直占用CPU进行循环
-
记录型信号量
- 用记录型数据结构表示
- 遵循了让权等待
1.2信号量机制实现互斥、同步
信号量机制实现进程互斥:在缓冲区前后分别执行P、V
- 划分临界区,设置互斥信号量mutex,初值为1
- 对不同的临界资源要设置不同的互斥信号量mutex1、mutex2……
信号量机制实现进程同步:前V后P
-
同步就是要保证一前一后执行两个操作
-
设置同步信号量S,初值为0
-
在前操作之后执行V(S),在后操作之前执行P(S)
信号量机制实现前驱关系: 每一对前驱关系都是一个进程同步问题,因此为每一对前驱关系设置一个同步信号量。
2.用信号量机制解决问题
2.1生产者消费者问题
-
生产者和消费者共享一个初始为空、大小为n的缓冲区
-
二者必须互斥的访问缓冲区(互斥)
-
只有缓冲区没满的时候,生产者才能把产品放入缓冲区,否则必须等待(同步)
-
只有缓冲区不空时,消费这才能从中取走产品,否则等待(同步)
-
- 实现互斥的P操作一定要在实现同步的P操作之后,否则死锁
- V操作不会导致进程阻塞,可以交换
- 生产产品,使用产品最好不要放到缓冲区去执行,压力会很大
2.2多生产者消费者问题
当缓冲区为1时,此问题可以不写互斥的P、V
分析这类问题要从事件的角度出发:盘子变空-------->放入水果
2.3吸烟者问题(单生产者)
2.4读写者问题
2.5哲学家进餐问题
-
每个进程都需要持有两个临界资源,容易死锁
3.管程
- 管程也是用来实现进程的互斥和同步,管程就是解决了信号量机制麻烦,易错问题。
- 管程相当于类,组成部分:
- 共享数据结构(类)
- 对数据结构操作的一组过程(函数)
- 共享数据设置初始值
- 通过函数才能访问共享数据
- 管程有一个名字
- 互斥特性由编译器执行,我们不需要关心
- 每次仅允许一个进程在管程内执行函数
- 可在管程中设置条件变量、等待、唤醒操作解决同步问题
4.死锁
4.1概述
死锁:各进程互相等待对方手里的资源,导致各进程都阻塞,无法推进
- 至少两个及以上进程才会死锁
- 必为阻塞态,缺少资源
饥饿:长期得不到想要的资源,如短进程优先,某个长进程就会饥饿
- 一个进程饥饿
- 就绪态(缺CPU)、阻塞态(缺I/O设备)
死循环:某个进程执行一直挑不出某个循环,逻辑bug
-
死循环只有一个进程
-
死循环可以处于运行态,是管理者的问题,不是操作系统的问题
死锁产生的4个必要条件:
- 互斥条件:对必须互斥使用资源的争抢
- 不剥夺条件:未使用完之前,不能由其他进程强行夺走
- 请求和保持条件:已经有了至少一个资源,但又提出了新的资源请求
- 循环等待条件:存在资源的循环等待链
存在循环等待的时候未必死锁,如果同类资源大于1,就不会死锁。
对不可剥夺资源的不合理分配就会发生死锁(互斥信号量在同步信号量之前会死锁)
死锁处理策略:
4.2预防死锁
破坏死锁产生条件之一
破坏互斥条件:
- 将互斥资源变为共享资源,就不会争抢了
- 缺点:很多时候互斥资源不可以改为共享的,为了系统的安全,很多时候无法破坏互斥性
破坏不剥夺条件:
- 方案一:当某个进程请求新的资源得不到满足,就立即释放现有资源,需要的时候再申请
- 方案二:某个进程所需资源被其它进程占用,可以由操作系统协助,将想要的资源强行抢过来,这种方式考虑的是优先级
- 缺点:
- 实现起来相对复杂
- 释放已有资源可能造成前面工作失效,因此只适合易于保存和恢复的资源,如CPU
- 申请释放资源会增加系统开销,降低系统吞吐量
- 采用方案一可能会饥饿
破坏请求保持条件:
- 采用静态分配法,一次申请完他所需要的全部资源
- 缺点:资源利用率低,可能饥饿
破坏循环等待条件:
- 采用顺序资源分配法,给资源编号,按照从小到大申请
- 缺点:不方便增加新设备,要重新编号
- 实际使用资源顺序和编号不一致,造成资源浪费
- 必须按顺序申请,编程麻烦
4.3避免死锁
安全序列:系统按照某种序列分配资源,每个进程都能顺利完成,即处于安全状态。
安全序列可以有多个。
系统处于不安全状态可能会死锁,死锁一定是处于不安全状态。
银行家算法核心思想:进程提出申请资源,先预测一下是否会导致进入不安全状态,如果会,不答应这次请求,先让进程阻塞等待。
4.4死锁的检测和解除
死锁的检测:
数据结构:来保存资源的请求和分配信息
上述请求让p1先执行,p1执行完成后,释放资源和请求,p2就可以执行了。这是一种安全状态,最终能消除所有边,一定不会发生死锁。
死锁定理:如果某时刻系统的资源分配图时不可完全简化的,就发生了死锁。
最终还连着边的进程就是处于死锁状态的进程。
死锁解除方法:
我们可以选择下面这些进程用来牺牲,以解除死锁:
- 优先级低的
- 已经执行的时间较短
- 还要很长时间才能完成的
- 进程已经使用的资源多的
- 进程是批处理式,而非交互式