• 死锁的条件、原因以及场景分析


    死锁可以称为进程死锁。那么是在多进程(并发)情况下可能会出现的。

    指的是多个进程因为竞争资源而造成的僵局(互相等待),没有外力,那么所有进程都会无法向前推进。

    所以是在操作系统和并发程序设计中需要特别考虑的问题。

    因此,可以可以得出如下的场景和必备条件。

    场景:

    • 系统资源的竞争。只有资源不足时才会出现死锁可能,另外,可剥夺资源的竞争是不会引发死锁的;
    • 进程推进顺序不对。多进程在运行时,请求和释放资源的顺序不当。
    • 系统资源分配不当。

    四大必要条件:

    • 互斥:进程对分配到的资源排它性使用。独占资源,是由资源本身的属性决定的。
    • 请求和保持:保持已有资源,同时请求新的资源,在请求过程中以及因为没有得到新资源而阻塞,已有资源仍然保持;
    • 不可剥夺:进程已有的资源在使用完之前不能被剥夺,只能自己释放;
    • 环路等待:必然存在一个进程资源环形请求链。

    死锁预防:打破之前四个条件

    • 打破互斥在实际中应用不大;
    • 打破请求与保持,可以实行资源预先分配策略,即进程在运行前一次性申请所需要的全部资源,如果不能满足,则暂不运行。实际应用中,进程在执行时是动态的,不可预测的,并且资源利用率低,降低了进程并发性。
    • 打破不可剥夺,当请求新资源不能满足,需要释放已有资源,系统性能受到很大降低
    • 打破循环等待:实行资源有序分配策略。可以将资源事先分类编号,按号分配,使进程在申请、占用资源是不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。但是也有问题,合理编号困难,增大系统开销,另外也增加了进程对资源的占有时间。

    死锁避免:

      不限制进程有关申请资源的命令,而是对进程所发出的每一个申请资源命令加以动态地检查,并根据检查结果决定是否进行资源分配。就是说,在资源分配过程中若预测有发生死锁的可能性,则加以避免。这种方法的关键是确定资源分配的安全性。

      银行家算法(1968年):允许进程动态地申请资源,系统在每次实施资源分配之前,先计算资源分配的安全性,若此次资源分配安全(即资源分配后,系统能按某种顺序来为每个进程分配其所需的资源,直至最大需求,使每个进程都可以顺利地完成),便将资源分配给进程,否则不分配资源,让进程等待。

    死锁检测与修复:

      预防和避免的手段达到排除死锁的目的是很困难的。一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。

    ----------------------------------------------------------------------------------------------------

    死锁常见的场景如下:

    忘记释放锁:

    void data_process()
    {
        EnterCriticalSection();
    
        if(/* error happens, forget LeaveCriticalSection */)
            return;
    
        LeaveCriticalSection();
    }
    

      

    单线程重复申请锁(所以单线程的时候也有可能进入死锁)

    void sub_func()
    {
        EnterCriticalSection();
        do_something();
        LeaveCriticalSection();
    }
    
    void data_process()
    {
        EnterCriticalSection();
        sub_func();
        LeaveCriticalSection();
    }
    

      

    多线程多锁申请

    void data_process1()
    {
        EnterCriticalSection(&cs1);  // 申请锁的顺序有依赖
        EnterCriticalSection(&cs2);
        do_something1();
        LeaveCriticalSection(&cs2);
        LeaveCriticalSection(&cs1);
    }
    
    void data_process2()
    {
        EnterCriticalSection(&cs2);  // 申请锁的顺序有依赖
        EnterCriticalSection(&cs1);
        do_something2();
        LeaveCriticalSection(&cs1);
        LeaveCriticalSection(&cs2);
    }
    

      

    多线程环形锁

    编程中如何来避免:

    • 检查有没有忘记释放锁
    • 如果自己模块可能重复使用一个锁,建议使用嵌套锁
    • 建议使用库里面的锁
    • 如果某项业务需要获取多个锁,保证锁按某种顺序来获取
    • 编写简单测试用例验证是否存在死锁

    参考:https://www.cnblogs.com/kuliuheng/p/4071555.html

  • 相关阅读:
    使用 gdb 对程序进行汇编级调试
    日记:暂时不玩了
    真经一句话
    2 service and configuration design dimensions——ACE读书笔记
    电影经典对白
    excel 中分段统计的使用
    asp.net url 重写解决方案
    OpenLayers项目分析(七)地图表现
    Geoserver学习(四)——WMS工程分析之Java包介绍
    OpenLayers项目分析(六)数据渲染分析
  • 原文地址:https://www.cnblogs.com/zhang-qc/p/8869377.html
Copyright © 2020-2023  润新知