19.进程同步与死锁——死锁处理

1.引出死锁

再看生产者-消费者的信号量解法,之前的例子:

//用文件定义 共享缓冲区
int fd = open("buffer.txt");
write(fd, 0, sizeof(int));//写in
write(fd, 0, sizeof(int));//写out

//信号量的定义和初始化
semaphore full = 0;//生产的产品的个数
semaphore empty = BUFFER_SIZE;//空闲缓冲区的个数
semaphore mutex = 1;//互斥信号量

//生产者
Producer(item)
{
    P(empty);//生产者先判断 缓存区个数 empty是否满了,empty == 0,阻塞
    P(mutex);//操作文件前,用mutex防止其他进程操作该文件
    读入in,将item写到in的位置上
    V(mutex);//使用完文件,释放文件资源
    V(full);//生产者生产产品,增加full,消费者就可以消费了
}

//消费者
Consumer()
{
    P(full);//当full == 0,缓冲区空了,阻塞
    P(mutex);
    读入out,从文件中的out位置读出到item,打印item;
    V(mutex);
    V(empty);//消费者消耗产品,增加缓冲区个数,增加empty,生产者就可以继续生产了
}

上边的例子 Producer 先调用的 P(empty) 后调用的 P(mutex),如果换个位置呢?

// 设 mutex初值是1,empty初值是0,缓冲区取满了
Producer(item)
{
    P(mutex);  // P(mutex) 会把 mutex 变成 0
    P(empty);  // P(empty) 会把 empty 变成 -1,生产者阻塞
    读入in,将item写到in的位置上
    V(mutex);
    V(full);
}

P(semaphore s)
{
    s.value--;
    if(s.value < 0){
        sleep(s.queue);
    }
}

//消费者
Consumer()
{
    P(mutex);  // mutex是0,执行P(mutex)将mutex变成 -1,消费者阻塞,此时 消费者 和 生产者都阻塞了
    P(full);
    读入out,从文件中的out位置读出到item,打印item;
    V(mutex);
    V(empty);
}

此时 消费者 和 生产者都阻塞了,
生产者要执行,需要有人把empty释放了,即 消费者要执行 V(empty),当前消费者卡在 P(mutex)
消费者要执行,需要生产者把 mutex释放了,生产者要执行 V(metux),生产者卡在 上边的 P(empty)

生产者在P(empty)往下执行,依赖于消费者,消费者要往下执行,又依赖生产者P(empty)下边的指令。形成环路等待,死锁。

如果很多进程都没法推进,会导致计算机不工作,CPU利用率低

2.死锁的成因

这里写图片描述

以车辆占用道路为例:
车辆 A 行驶在 道路1(上边 左右方向的线) 上,想申请 道路2 (右边 上下方向的线)
道路2 被 车辆B 占用着,车辆 B 要申请 道路3(下边 左右方向的线)
道路3 被车辆C 占用着,车辆C 要申请 道路4(左边 上下方向的线)
道路4 被车辆D 占用着,车辆D 要申请 道路1,然而 道路1 被 车辆A 占用着

死锁的成因:
资源互斥(比如信号量、打印机),进程占有资源,同时 又再去申请其他资源,造成环路等待,形成死锁

3.死锁的必要条件

  • 互斥使用(Mutual exclusion)
    • 资源的固有特性,如道口
  • 不可抢占(No preemption)
    • 资源只能自愿放弃,如 车开走以后
  • 请求和保持(Hold and wait)
    • 进程必须占有资源,再去申请
  • 循环等待(Circular wait)
    • 在资源分配图中存在一个环路

4.死锁的处理

4.1 死锁处理方法概述

  • 死锁预防
    • 破坏死锁出现的条件,不要 占有资源 又申请其他资源
  • 死锁避免
    • 检测每个资源请求,如果造成死锁就拒绝
  • 死锁检测 + 恢复
    • 检测到死锁出现时,让一些进程回滚,让出资源
  • 死锁忽略
    • 好像没有出现死锁一样

4.2 死锁预防的例子

4.2.1 在进程执行前,一次性申请所有需要的资源,不会占有资源再去申请其他资源

比如 代码第3句 需要一个信号量,第10句需要一个信号量,在程序开始,就获取这2个信号量

缺点:

  • 需要预知未来,变成困难。要知道所有用到的资源,如果代码 if 中用到了 信号量,在程序开始 也要申请该信号量。如果本次执行,不走这个 if,占用的这个信号量就没有被利用
  • 许多资源分配后 很长时间才使用,资源利用率低

4.2.2 对资源类型进行排序,资源申请必须按序进行,不会出现环路等待

缺点: 造成资源浪费
对资源进程排序,如果需要10号资源,需要把 10号之前的资源 全部申请了,造成资源的浪费

4.3 死锁避免

4.3.1 安全序列

安全状态: 如果系统中的左右进程 存在一个可完成的执行序列 P1,… ,Pn,则称系统处于安全状态
安全序列:所有进程都可以执行完的序列

这里写图片描述
上图含有 5个 进程:P0-P4
Allocation :占有的资源,以P1 为例,占用资源A 3个,资源B 0个,资源C 2个
Need:需要的资源
Available:系统中 剩余的资源

什么方法能让 这些进程都执行完?
右边的问题中 选项 A 是安全序列
当前系统 剩余资源时 ABC = 230,给 P1,P1可以执行完,P1 执行完 Available ABC = 532
P3 可以执行,P3 执行完,Available ABC = 743
其他进程都可以执行

4.3.2 银行家算法

int Available[1..m]; //每种资源剩余数量
int Allocation[1..n, 1..m];  //已分配资源数量
int Need[1..n, 1..m];  //进程还需的各种资源数量
int Work[1..m];  //工作向量
bool Finifh[1..n];  //进程是否结束

Work = Available;
Finifh[1..n] = false;
while(true)
{
    for(i = 1; i <= n; i++)
    {
        // Need[i] <= Work 这个任务是可以完成的
        if(Finish[i] == false && Need[i] <= Work)
        {
            Work = Work + Allocation[i];  // Work 累加系统曾分配给 i 的资源
            Finish[i] = true;
            break;
        } else {
            goto end;
        }
    }
}

End: for(i = 1; i <=n; i++)
        if(Finish[i] == false)
            return "deadlock";

时间复杂度是 T(n) = O(m* n^2),m是资源数,n是进程数
系统中的 资源和 进程都很多,执行的代价还是很大的

银行家算法实例:
这里写图片描述

应用时,首先假装分配,然后调用 银行家算法,如果给进程1分配资源,进程1执行完,其他进程都不能执行,则拒绝 进程1 的资源申请

4.4 死锁检测 + 恢复:发现问题再处理

  • 定时检测 或者是 发现资源利用率低时检测
  • 选择哪些进程回滚?回滚的依据是什么,是优先级,还是占有资源多少
  • 如何实现回滚?那些已经修改的文件怎么办?
    回滚容易出错,比如存款程序,用户已经往账户里打钱,信息已经写到一个文件里了,现在要回滚,这个钱已经在银行了。回滚会出错。

4.5 死锁忽略

Windows 和 Linux 都 采用了 死锁忽略的方法
- 死锁忽略的处理代价最小
- 这种机器上出现死锁的概率比其他机器低
- 死锁可以用重启来解决,PC重启造成的影响小
- 死锁预防让编程变得困难

4.6 总结

  • 死锁预防
    • 引入太多不合理因素
  • 死锁避免
    • 每次申请都执行银行家算法,效率太低
  • 死锁检测 + 恢复
    • 恢复很不容易,进程造成的改变很难恢复
  • 死锁忽略
    • 死锁出现是不确定的,可以用重启来处理死锁
    • 大多数非专门的操作系统都用 死锁忽略,如 UNIX,Linux,Windows
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值