饥饿与活锁

作者: 贪婪的君子 | 来源:发表于2017-05-28 12:22 被阅读15次

    某次在餐馆......
    服务员!你是不是歧视我啊,我等了半个多小时了,为啥别的桌菜都上齐了,我这儿还只能喝茶!

    虽然不至于饿死,但是饥饿感还是有的。
    上述的这种生活场景在计算机的并发编程中也是比较容易遇到的,这个问题主要就是资源分配策略的不公平导致的,和死锁相类似,饥饿的进程也是会长时间的等待,无法继续向下执行。

    饿死了


    当进程长时间得不到所需资源,使进程难以推进时,我们称发生了进程饥饿,若是长时间的处于饥饿状态导致后续已没有完成该进程任务的必要时,我们就称这个进程饿死了。

    进程的饥饿状态也是由竞争资源引起的,但却是由于实力(优先级等)太弱,导致很难争的过其他进程,这一点和死锁是不同的,与死锁不同的方面还有很多,我们考虑如下几点:

    1. 进程状态:死锁进程都是处于等待态,饥饿进程是处于运行就绪态中的忙式等待状态(比如在一个while循环中无法跳出)。

    在忙式等待中发生的界,我们也称其为活锁

    1. 死锁进程等待永不被释放的资源,饿死的进程则是等待可以被释放,但不会分配给自己的资源
    2. 死锁一定发生循环等待,但是饿死则不一定。

    所以,死锁检测算法无法检测到饿死状态。

    1. 死锁涉及的进程至少是两个,但是饥饿却可能只有一个

    一般情况下,想要解决饥饿问题,就会需要对进程竞争资源的竞争力(特权级等)进行评估,竞争力强(特权级高)的进程优先分配资源,然后才是竞争力弱的。
    但若是只对竞争力进行静态的评估,就会出现当系统中存在一个竞争力弱的进程,其余进程的竞争力都强的时候,这个竞争力弱的进程便难以得到所需资源的情况。所以我们想到为进程先进行静态的评估,随后的程序执行中,动态的改变进程的竞争力(提高进程的竞争力/特权级)。

    难道还不许一个进程有自己的成长空间了?
    对了,这项技术被称为老化,毕竟老而位尊嘛。

    过河问题


    如图假设两个村子之间有一条河,河上有8块石头,每块石头上同时只能站一个人,东西两岸的村民要过河,分析其过河的方法。


    过河问题

    我们来分析一下,假设我们限定东西两岸的村民不能同时过河,也即只要有一岸的村民在使用桥,那么,另一岸的村民便不能使用,给出PV操作实现的算法:

    semaphore s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8  = 1;
    int EastCount = WestCount = 0;
    //东岸过河
    while (1)
    {
        while ( WestCount > 0)
            ;
        EastCount += 1;
        P(s1);
        arrive at stone-1;
        V(s1);
        P(s2);
        arrive at stone-2;
        V(s2);
        P(s5);
        arrive at stone-5;
        V(s5);
        P(s6);
        arrive at stone-6;
        V(s6);
        P(s4);
        arrive at stone-4;
        V(s4);
        P(s3);
        arrive at stone-3;
        V(s3);
    }
    

    西岸过河情况类似,同样是先检测有没有东岸的人在过河,然后才能决定是否可以过河。
    这种解决方案非常简单,而且清晰明了,但是却有潜在的弊端,即饥饿。
    假设东岸过河的人数源源不断,那么西岸的人便一直无法过河,就产生了饥饿状态(估计等的花都谢了,如果这时候在西岸边开个餐馆,说不定很赚哦)。这是分配规则不公平所导致的。

    换一种分析方式,假设两岸的村民都可以同时过河,那么我们可以发现,一旦两岸过河的总人数超过了五人(6人),那么这两岸的村民可能都将无法过河,卡死在桥上。

    假设情况:两岸各有三名村民走到石块上,无论怎么走,都会产生死锁。

    所以要解决饥饿,死锁还得并行度高,就可以采用有序分配法,顺序申请,顺序释放:

    semaphore smax = 5; //最大过河人数
    semaphore s1 =  s2 = s3 = s4 = s5 = s6 = s7 = s8 = 1;
    //东岸过河
    East()
    {
        P(smax);
        P(s1);
        at stone-1;
        V(s1);
        P(s2);
        at stone-2;
        V(s2);
        P(s5);
        at stone-5;
        V(s5);
        P(s6);
        at stone-6;
        V(s6);
        P(s3);      //有序的申请,保证自己能过河
        P(s4);
        at stone-4;
        V(s4);
        at stone-3;
        V(s3);
        V(smax);
    }
    

    西岸过河方式类似,同时有序分配法来操作,留待读者自行思考。

    小结


    哲学家问题是一个经典的问题,不光是能用在死锁上,还能用来描述饥饿的问题,简单的介绍一下,如果五名哲学家同时拿起右叉,然后检查自己身旁是否有左叉,若没有左叉,放下右叉,等待。
    就这么两个动作循环着做,就是饥饿问题的描述了。
    也许饥饿问题不如死锁问题严重,但是一个进程一投入运行就持续保持饥饿,难以得到运行资源,那这个进程不就没什么意义了吗?

    哲学家:本来还想夸夸你,终于肯放过我了,没想到......

    相关文章

      网友评论

        本文标题:饥饿与活锁

        本文链接:https://www.haomeiwen.com/subject/bexhfxtx.html