我们先来看下面一段代码:
//inside1、inside2是进程P1和P2在内存中保存的标志,表示进程是否在临界区内 inside1 = false; inside2 = false; //进程P1 process P1 begin while(inside2) ; //循环测试 inside1 := true; 临界区; inside1 := false; end; //进程P2 process P2 begin while(inside1) ; //循环测试 inside2 := true; 临界区; inside2 := false; end;
代码逻辑很清晰,就是进程P1或者P2想进入临界区之前,先去判断对方是否在临界区内,如果在的话,就一直循环等待,否则就进入临界区,然后“关门”(挂锁)。第一眼看似乎是没什么问题,但是如果进程在执行期间,比如P1先执行,在执行挂锁(inside1 = true)之前,发生了中断,进程P2也开始了执行,此钱P1的锁还没有挂上,因此进程P2可以进入临界区,在临界区内执行的时候,P2也发生了中断,P1恢复执行,因为之前已经执行过判断是否可以进入临界区的代码,因此此时同样的可以进入临界区,在这种情况下,两个进程同时的进入了临界区,进程的执行就会出现错误。
虽然在上面的进程P1和P2执行的过程中发生了很多恰巧的事(小概率事件),P1在挂锁前中断、P2在临界区执行时中断、P1和P2进程能在对方在中断时抢占CPU,这几个事件组合在一起,概率就更加的小了,但是仍然的是存在问题的。
这个时候你可能会想,我在判断之前先挂上锁呢,我们把代码的顺序调整一下,大家请看:
//... //进程P1 process P1 begin inside1 := true; while(inside2) ; //循环测试 临界区; inside1 := false; end; //进程P2 process P2 begin inside2 := true; while(inside1) ; //循环测试 临界区; inside2 := false; end;
这样的话,进程P1、P2在并发执行的时候就没有问题了么,我们来看这样一种情况,P1先执行,挂锁成功,假设在成功之后,P1发生了中断,进程P2开始执行,此时P2同样可以挂锁,但是在判断是否可以进入临界区时,则无法成功,会一直在循环中判断,当P1再次恢复执行时,尴尬的事情发生了,P1也无法进入临界区了,因为P2同样把锁给挂上了。
上面是两种软件同步机制的实现,第一个是双标志法先检查,第二个是双标志法后检查,但是两个方法都无法真正的解决进程同步问题。双标志法先检查法可能会让两个进程同时进入临界区,双标志法后检查法可能会让两个进程都无法进入临界区,形成死锁问题。
虽然通过软件方式也可以实现诸进程互斥的进入临界区的问题,比如Peterson算法,但是有一定的难度,并且存在很大的局限性,因而现在已经很少使用了,下面我们来看下别的几种方式。










