时间:2023-02-15来源:系统屋作者:zhijie
死锁的避免
死锁出现有4个必要条件:
1.互斥: 资源只能同时被一个进程使用
2.占有且等待: 一个进程在等待别的资源的时候, 将继续占有其拥有的资源
3.非抢占: 不能强行抢占别人占有的资源
4.循环等待: 在满足如上3个条件的情况下, 出现循环等待即出现死锁
要避免死锁也是从这4个条件上下手:
1.互斥: 这个是为了资源功能正常运转, 无法避免
2.占有且等待: 让进程一开始就申请所有资源才能运行。问题是效率低下, 进程可能要等待很长时间, 资源可能被控制很长时间, 程序也需要最开始就知道需要使用哪些资源;
3.非抢占: 根据进程优先级让申请资源的进程释放自己之前拥有的资源或者抢占别的进程的资源, 靠谱, 唯一的问题在于资源的使用不一定有那么容易的保存和恢复(很多硬件不像处理器那样可以随意切换使用进程的)
4.循环等待: 给资源定义一个序列, 进程只能按照序列申请资源, 会导致进程执行效率大大降低, 所以主流做法是如下两种
如上几种避免办法都有各种各样的问题, 所以一般不采用, 现在采用最多的方案还是从第4点出发, 只不过不预先避免, 而是动态探测:
1.如果一个进程启动或者新增资源需求会导致死锁, 则不允许此分配
典型的算法如银行家算法, 此方法的弊端是需要知道一个进程将来所需要占用的资源
2.允许所有请求, 周期性的进行检测死锁
动态检测, 运行效率高, 但是如果出现死锁频率比较高, 则系统运行效率会比较低。
综合所有的死锁避免的方法的对比如下:
编程界面
多进程之间的互斥与同步方案有了如上提到的系列硬件支持之后, 就需要考虑操作系统对有并发编程的程序员们提供的编程界面了。
信号量
信号量是在内存中维护了一个int, 每次操作对该int进行++或者--。
对操作者提供了两个接口:
1.semWait
该接口检查int值, 如果该值大于0, 就将该值--, 并进入临界区; 否则就阻塞检测该值知道大于0;
2.semSignal
该接口将int值++, 并通知受阻的所有进程。通知哪个进程有的采用FIFO策略, 有的采用随机策略。
管程
信号量的方式比较灵活, 让程序员可以任意控制临界区以及交互设计, 大部分现在程序也都采用了类似的方案, 这是一个相对底层但是功能强大的方案。
但是有人提出了信号量的操作分散, 在模块中任何位置都可能出现, 造成程序编写和维护困难, 也容易出bug, 所以在70年代, 有人提出了管程的概念, 笔者在实际工作中尚未使用管程来实现进程间互斥和同步。
管程底层跟信号量类似, 只是他把所有加锁解锁的逻辑全部封装在一个类里面, 所有关于该临界资源的操作都在这个类中以函数的方式呈现, 除了这个类之外其他任何地方都看不到锁。这样就实现了锁相关逻辑集中在一个地方。
在一个类里面可以有多把锁, 跟信号量类似, 针对每把锁, 在该类的函数里可以用类似semWait和semSignal的接口等待该锁或者释放该锁。
2023-02-15
Linux系统grep正则表达式的介绍2023-02-15
Linux系统TSO的实现原理2023-02-15
Linux系统NBMA和BMA的交换方式介绍在Linux系统中使用xargs命令可以解决不少问题,特别是xargs命令再配合find命令,能够发挥出更加惊人的效果。本文就来为大家介绍一下Linux系统xargs命令的用法。...
2023-02-14
Linux系统的进程是由线程组成的,当然Linux进程下的线程数是不固定的,可以是一个进程,也可以是多个进程。本文就来教大家Linux系统如何查看进程的线程数?...
2023-02-14