介绍
互斥是指进程之间的竞争关系
临界区的使用原则
- 没有进程在临界区时,想进入临界区的进程可以进入
- 不允许两个进程同时处于临街区
- 临界区外运行的进程不得阻塞其他进程进入临界区
- 不得使进程无限期等待进入临界区
解决方案
软件解决方案
- Dekker解法
- Peterson解法
硬件方案
- 屏蔽中断
- TSL指令
几种软件解决方法
第一种
当P进程在while(free)
之后并且free=true
语句之前完成时间片执行,被调度下CPU,此时Q进程此时被调度到CPU上执行并且进入临界区,但是没有完全执行完临界区就完成时间片被调度下CPU后,P进程又被调度上CPU继续执行进入临界区,此时有两个进程处在临界区中,违反了临界区的使用原则
第二种
如果Q进程不想进入临界区,则会导致P一直等待,不能进入临界区,违反了临界区的使用原则
第三种
当P进程执行完pturn=true
之后被调度下CPU,然后Q进程被调度上CPU执行qturn=true
之后也被调度下CPU,此时P进程将会一直执行while(qturn)
导致不能进入到临界区
DEKKER算法
引入turn变量来标识应该哪个进程执行。
缺点
- 就算不使用临界区也会阻塞别的进程
- 一直在测临界区是否是否空闲,浪费处理器资源
- 只能处理固定顺序的进程序列
PETERSON算法
缺点
- 临界区范围大,不能保证所有指令并发执行
- 开关中断只能作用于一个处理器,所以适用于单处理器
- 用户程序不能使用特权指令
屏蔽中断
开关中断指令
TSL指令
TSL指令其工作如下所述:它将一个存储器字读到一个寄存器中,然后在该内存地址上存一个非零值。读数和写数操作保证是不可分割的—即该指令结束之前其他处理机均不允许访问该存储器字。执行TSL指令的CPU将锁住内存总线以禁止其他CPU在本指令结束之前访问内存。
为了使用TSL指令,我们必须用一个共享变量lock来协调对共享内存的访问。当lock为0时,任何进程都可以使用TSL指令将其置为1并读写共享内存。当操作结束时,进程用一条普通的MOVE指令将lock重新置为0。
如上图所示,其中展示了使用四条指令的汇编语言例程。第一条指令将lock原来的值拷贝到寄存器中并将lock置为1,随后这个原先的值与0相比较。如果它非零,则说明先前已被上锁,则程序将回到开头并再次测试。经过或长或短的一段时间后它将变成0(当前处于临界区中的进程退出临界区时),于是子例程返回,并上锁。清除这个锁很简单,程序只需将0存入lock即可,不需要特殊的指令。
进程在进入临界区之前先调用enter_region。这将导致忙等待,直到锁空闲为止。随后它获得锁变量并返回。在进程从临界区返回时它调用leave_region,这将把lock置为0。
XCHG指令
总结
-
浪费CPU:上面提到了几种实现互斥的方案,本质上说他们都是一种采用忙等待的方式,并且不断地检查当前条件是否允许其运行。通过进程之间的同步操作可以避免这种资源的浪费
-
优先级反转问题:现在假设某一时刻,阴差阳错也好,还是什么也好,L进入了临界区,但是运行到中途,时间片到期了,这时候H处在ready状态,但是由于L还处在临界区,那其实H也无法运行,而L又没有时间片。结果就是大家就这么干耗着
参考资料
Dekker算法与Peterson算法-处理两个进程间互斥 操作系统–进程同步与死锁