第二章 处理器管理(第二部分)
2.11 进程互斥的软件实现方法
2.11.1 单标志法
算法思想:两个进程早访问完临界区后会把使用临界区的权限转交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程赋予。
实现同一时刻最多只允许一个进程访问临界区。
主要问题:不遵循“空闲让进”原则
2.11.2 双标志先检查
算法思想:设置一个布尔型数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿。每个进程再进入临界区之前先检查当前有没有别的进程想进入临界区,如果没有,则把自身对应的标志flag[i]设置为true,之后开始访问临界区。
主要问题:不遵循“忙则等待”原则
2.11.3 双标志后检查
前一个算法的问题是先“检查”后“上锁”,但是这两个操作又无法一气呵成,因此导致了两个进程同时进入临界区的问题。
算法思想:双标志先检查法的改版。先“上锁”后“检查”
主要问题:不遵循“空闲让进、有限等待”原则,可能导致“饥饿”
2.11.4 Peterson算法
算法思想:如果双方都争着想进入临界区,那可以让进程尝试主动让对方先使用临界区。
**主要问题:**不遵循“让权等待”原则,会发生“忙等”
2.12 进程互斥的硬件实现方法
2.12.1 中断屏蔽方法
实现:利用“开/关中断指令”
优点:简单、高效
缺点:不适合用于多处理机;只适用于操作系统内核进程,不适用于用户进程
2.12.2 TestAndSet(TS指令/TSL指令)
简称TS指令,也有地方称为TestAndSetLock指令,或TSL指令。TSL指令时用硬件实现的,执行的过程不允许被中断,只能一气呵成。
实现:old记录是否已被上锁;再将lock设为true;检查临界区是否已被上锁。
优点:实现简单,无需像软件实现方法那样严格检查释放会有逻辑漏洞,适用于多处理机环境
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致“忙等”
2.12.3 Swap指令(XCHG指令)
实现:与TSL指令并无太大区别
优点:实现简单,无需像软件实现方法那样严格检查释放会有逻辑漏洞,适用于多处理机环境
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致“忙等”
2.13 信号量机制
2.13.1 整型信号量
用一个整数型变量作为信号量,数值表示某种资源数
整型信号量与普通变量的区别:对信号量只能执行初始化、P、V三种操作
整型信号量存在的问题:不满足让权等待原则
2.13.2 记录型信号量
S.value表示某种资源数,S.L指向等待该资源的队列
P操作中,一定是先S.value–,之后可能需要执行block原语
V操作中,一定是先S.value++,之后可能需要执行wakeup原语
注意:要能够自己推断再什么条件下需要执行block(当前允许的进程从运行态—>阻塞态)或wakeup(被唤醒进程从阻塞态—>就绪态)
作用:用记录型信号量实现系统资源的“申请”和“释放”、进程互斥、进程同步
2.13.3 实现进程互斥
实现进程互斥的步骤:
1、分析并发进程的关键活动,划定临界区
2、设置互斥信号量mutex。初始值为1
3、在临界区之前执行P(mutex)
4、在临界区之后执行V(mutex)
注意:对不同的临界资源需要设置不同的互斥信号量。P、V操作必须成对出现。
2.13.4 实现进程同步
让各并发进程按照要求有序地推进
实现进程同步的步骤:
1、分析什么地方需要实现“同步关系”,即必须保证“一前一后”执行的两个操作
2、设置同步信号量S,初始为0
3、在“前操作”之后执行V(S)
4、在“后操作”之前执行P(S)
2.13.5 实现进程的前驱关系
每一对前驱关系都是一个进程同步问题。
实现步骤:
1、分析问题,画出前驱图,把每一对前驱关系都看成一个同步问题
2、为每一对前驱关系设置同步信号量,初值为0
3、在“前操作”之后执行V操作
4、在“后操作”之前执行P操作
2.14 生产者消费者问题
2.15 多生产者多消费者
2.16 吸烟者问题
2.17 读者-写者问题
2.18 哲学家进餐问题
2.19 管程
2.19.1 引入管程的原因
解决信号量机制编程麻烦、易出错的问题
2.19.2 管程的定义与基本特征
管程的定义
管程是一种特殊的软件模块,有这些 部分组成:
1、局部与管程的共享数据结构说明
2、对该数据结构进行操作的一组过程
3、对局部于管程的共享数据设置初始值的语句
4、管程有一个名字
基本特征
1、局部于管程的数据只能被局部于管程的过程所访问
2、一个进程只有通过调用管程内的过程才能进入管程访问共享数据
3、每次仅允许一个进程在管程内执行某个内部过程
2.19.3拓展
2.20 死锁的概念
2.20.1 死锁的定义
各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进
2.20.2 进程死锁、饥饿、死循环的区别
2.20.3 死锁产生的必要条件
产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。
1、互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁
2、不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放
3、请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放
4、循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求
注意:发生死锁时一定有循环等待,但是发生循环等待时未必死锁。
2.20.4 发生死锁的时间
1、对系统资源的竞争。各进程对不可剥夺的资源的竞争可能引起死锁,对可剥夺的资源的竞争是不会引起死锁的。
2、进程推进顺序非法。请求和释放资源的顺序不当,也同样会导致死锁。
3、信号量的使用不当也会造成死锁。
2.20.5 死锁的处理策略
1、预防死锁。破坏死锁产生的四个必要条件中的一个或多个
2、避免死锁。用某种方法防止进入不安全状态,从而避免死锁
银行家算法
3、死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措施解除死锁。