软件实现临界区互斥的方法一览

在考虑写代码之前应该先考虑我们要用什么数据结构?以及该数据有什么意义。

算法一: 单标志法

P0:
{
    while(turn != 0) ;
     // critical section
     turn  = 1; // 退出区
     // remainder section
}

P1:
{
    while(turn != 1) ;
     // critical section
     turn  = 0; // 退出区
     // remainder section
}

在这里,为了实现互斥使用了一个共享变量turn。
为什么有效?

在任意时刻turn的取值只能为0或1.因此条件while(turn != X)有且仅有一个会被满足,因而使得一个进程得以访问临界区。(至于turn被谁修改,什么时候修改,都不会对该过程产生不利影响)

有什么不足?

一个标识符只有2个信息。它只能表示1.P0干完了.2.P1干完了。 所以当P0干完了,P1又不干活的时候,P0还傻傻的等P1

turn表示什么?

turn其实是进程间约定的执行顺序。2个进程约好轮班工作,一个在干完活了通知另一个,反复交替。turn可以理解为许可证,只有持有turn的进程才能进去工作。就好像看病取票排队一样。

算法二:

P0:
{
    while(busy) ;
    busy=1;
     // critical section
     busy  = 0; // 退出区
     // remainder section
}

P1:
{
    while(busy) ;
    busy=1;
     // critical section
     busy  = 0; // 退出区
     // remainder section
}

这是一个典型的错误方法。
为什么出错?busy表示什么?

busy像是一扇大门,先进去的人从里面反锁不让外面的人进来。里面的人出来以后再重新开门。但是busy也只有2个信息量,也就是开和关。当它开门的时候无法控制进入的数量。所以极有可能一下子进去好多人。

但是它解决了前面的一个问题:无法“空闲让进”。

算法三: Peterson 算法

P0:
{
    flag[0]=1;turn=0;
    while(flag[1]&&turn != 0) ;
     // critical section
     flag[0]=0;// 退出区
     // remainder section
}

P1:
{
    flag[1]=1;turn=1;
    while(flag[0]&&turn != 1) ;
     // critical section
     flag[1]=0;// 退出区
     // remainder section
}

flag是什么?

首先看循环等待条件flag[1]&&turn != 1,对其取反即为通过条件!flag[1]||turn==1 。因此进入临界区的条件是获得许可(turn==1)或者P1空闲(!flag[0])。flag为0表示进程很空,flag为1表示想要进入临界区(不一定进入)。这里可以形象地理解为2个进程都盯着对方,一旦对方空了下来,就马上冲过去。

这里的turn有点不一样!

这里不再是轮班工作了。而是在表达完进入的意愿后(flag置1)将turn设为自己。说白了就是争夺模式。最后只有一个进程抢到turn,另一就等待对方空闲退出。

这个算法其实也不太完美,通过以上分析很容易就能知道它只允许2个进程的并发。

算法4

警告:该算法自创,将来程序出了差错,我是不会负责的

结合一下前面几种方法,尽可能地减少信息量,还要解决多进程的并发问题。现在再整理一下思路。首先,需要一个大门。然后门后面需要取票排队。

Pi:
{
    while(true)
    {
        while(flag) ;//等待空闲
        flag=1;//占用
        turn=i;
        if(turn==i) break;
    }
    
     // critical section
     flag=0;// 退出区
     // remainder section
}

如何工作?

利用flag控制大门开关。当里面没人时,马上进入,进去后就赶紧把门反锁(flag=1)。此时是有可能多个进程同时溜进去的,怎么办呢?划拳把!(turn=i)总之不管怎么样,最后turn为这帮人中的某一个,因此有且仅有一个得以进入,其他的则被轰出门外重新寻找机会。

erow
46 声望5 粉丝