怎么解决死锁问题

1.最简单暴力的方法就是根据鸵鸟算法

 

       通俗理解就是像鸵鸟一样把头埋在沙子里,假装问题根本没有发生。数学家认为死锁是不可接受的,必须通过有效的策略来防止死锁的产生。工程师想要知道问题发生的频次,系统因为其他原因崩溃的次数和死锁带来的严重后果。如果死锁发生的频次很低,而经常会由于硬件故障、编译器错误等其他操作系统问题导致系统崩溃

2.银行家算法(分单/多资源的境况)

        这是 Dijkstra 在 1965 年提出的一种调度算法,它本身是一种死锁的调度算法。它的模型是基于一个城镇中的银行家,银行家向城镇中的客户承诺了一定数量的贷款额度。算法要做的就是判断请求是否会进入一种不安全的状态。如果是,就拒绝请求,如果请求后系统是安全的,就接受该请求。银行家算法就是对每个请求进行检查,检查是否请求会引起不安全状态,如果不会引起,那么就接受该请求;如果会引起,那么就推迟该请求。     

3.破环互斥性

        如果资源不被一个进程独占,那么死锁肯定不会产生。如果两个打印机同时使用一个资源会造成混乱,打印机的解决方式是使用 假脱机打印机(spooling printer) ,这项技术可以允许多个进程同时产生输出,在这种模型中,实际请求打印机的唯一进程是打印机守护进程,也称为后台进程。后台进程不会请求其他资源。我们可以消除打印机的死锁。

        后台进程通常被编写为能够输出完整的文件后才能打印,假如两个进程都占用了假脱机空间的一半,而这两个进程都没有完成全部的输出,就会导致死锁。在业务允许的情况下,减少请求资源的进程或线程数。

4.破坏保持等待的条件

        如果我们能阻止持有资源的进程请求其他资源,我们就能够消除死锁。一种实现方式是让所有的进程开始执行前请求全部的资源。如果所需的资源可用,进程会完成资源的分配并运行到结束。如果有任何一个资源处于频繁分配的情况,那么没有分配到资源的进程就会等待。很多进程无法在执行完成前就知道到底需要多少资源,如果知道的话,就可以使用银行家算法;还有一个问题是这样无法合理有效利用资源

还有一种方式是进程在请求其他资源时,先释放所占用的资源,然后再尝试一次获取全部的资源。

5.破坏不可抢占条件        

        破坏不可抢占条件也是可以的。可以通过虚拟化的方式来避免这种情况。

6.破坏循环等待条件

        循环等待条件可以通过多种方法来破坏。一种方式是制定一个标准,一个进程在任何时候只能使用一种资源。如果需要另外一种资源,必须释放当前资源。对于需要将大文件从磁带复制到打印机的过程,此限制是不可接受的。

        另一个条件就是统一给所有资源编号,进程可以在任何时间提出请求,但是所有的请求都必须按照资源的顺序提出。如果按照此分配规则的话,那么资源分配之间不会出现环。

死锁的检测

        死锁的检测就是基于向量的比较。每个进程起初都是没有被标记过的,算法会开始对进程做标记,进程被标记后说明进程被执行了,不会进入死锁,当算法结束时,任何没有被标记过的进程都会被判定为死锁进程。

何时去做死锁检测,一般来说,有两个考量标准:

  • 每当有资源请求时就去检测,这种方式会占用昂贵的 CPU 时间。
  • 每隔 k 分钟检测一次,或者当 CPU 使用率降低到某个标准下去检测。考虑到 CPU 效率的原因,如果死锁进程达到一定数量,就没有多少进程可以运行,所以 CPU 会经常空闲。

从死锁中恢复

1.通过抢占进行恢复

在某些情况下,可能会临时将某个资源从它的持有者转移到另一个进程。比如在不通知原进程的情况下,将某个资源从进程中强制取走给其他进程使用,使用完后又送回。这种恢复方式一般比较困难而且有些简单粗暴,并不可取。

2.通过回滚进行恢复

        如果系统设计者和机器操作员知道有可能发生死锁,那么就可以定期检查流程。进程的检测点意味着进程的状态可以被写入到文件以便后面进行恢复。检测点不仅包含存储映像(memory image),还包含资源状态(resource state)。一种更有效的解决方式是不要覆盖原有的检测点,而是每出现一个检测点都要把它写入到文件中,这样当进程执行时,就会有一系列的检查点文件被累积起来。

        为了进行恢复,要从上一个较早的检查点上开始,这样所需要资源的进程会回滚到上一个时间点,在这个时间点上,死锁进程还没有获取所需要的资源,可以在此时对其进行资源分配。

3.杀死进程恢复

        最简单有效的解决方案是直接杀死一个死锁进程。但是杀死一个进程可能照样行不通,这时候就需要杀死别的资源进行恢复。

 4.另外一种方式是选择一个环外的进程作为牺牲品来释放进程资源。

### ### 数据库与操作系统中的死锁问题解决策略 在并发系统中,数据库和操作系统的资源竞争可能导致**死锁(Deadlock)**现象。死锁是指两个或多个事务/进程彼此等待对方释放资源,导致所有相关任务都无法继续执行的状态。 #### 死锁的成因 死锁通常由以下四个必要条件共同作用形成: - **互斥**:资源不能共享,一次只能被一个任务使用。 - **持有并等待**:任务在等待其他资源时,不释放已持有的资源。 - **不可抢占**:资源只能由持有它的任务主动释放。 - **循环等待**:存在一个任务链,每个任务都在等待下一个任务所持有的资源。 在数据库系统中,事务对数据行加锁(如排他锁、共享锁)时,若多个事务交叉请求不同资源,就可能引发循环依赖,从而导致死锁[^3]。 --- #### 死锁检测机制 为了有效处理死锁,系统需要具备检测能力。常见的检测方法包括: - **等待图(Wait-for Graph)分析**:通过构建事务之间的等待关系图,检测是否存在环路,若有,则表示发生死锁。 - **超时机制**:为事务设置最大等待时间,超过该时间仍未完成则认为可能发生死锁,进行回滚处理。 - **日志分析**:在数据库日志中查找死锁相关的错误信息,例如 MySQL 的 `SHOW ENGINE INNODB STATUS` 可显示最近的死锁记录。 数据库管理系统会在检测到死锁后选择一个代价最小的事务进行回滚,以解除死锁状态[^1]。 --- #### 死锁解决方案 针对死锁问题,可以采取以下措施降低其发生的概率或快速恢复: ##### 1. 资源申请顺序一致性 确保所有事务按照相同的顺序访问资源,避免交叉锁定带来的循环依赖。例如,在更新表 A 和表 B 时,所有事务都应先锁定表 A,再锁定表 B [^2]。 ##### 2. 减少事务持锁时间 将事务拆分为多个较小的操作,减少事务的持续时间和锁定范围。例如,可以在获取所需数据后尽快提交事务,而不是在事务中执行大量逻辑处理。 ##### 3. 设置合理的隔离级别 适当调整事务的隔离级别,例如从“可重复读”改为“读已提交”,可以减少锁的粒度和持有时间,降低死锁风险。 ##### 4. 启用死锁自动检测与重试机制 多数数据库默认启用死锁检测机制,并在发生死锁时回滚其中一个事务。应用层可通过捕获死锁异常(如 MySQL 的 `Deadlock found when trying to get lock` 错误),实现自动重试逻辑: ```python import pymysql def execute_with_retry(max_retries=3): for attempt in range(max_retries): try: conn = pymysql.connect(...) with conn.cursor() as cursor: cursor.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1") cursor.execute("UPDATE orders SET status = 'paid' WHERE user_id = 1") conn.commit() return except pymysql.err.Deadlock: print(f"Deadlock detected, retrying... (attempt {attempt + 1})") conn.rollback() print("Max retries reached, giving up.") ``` ##### 5. 操作系统层面的资源调度优化 在操作系统中,可以通过限制并发进程数量、引入资源分配优先级、使用银行家算法等手段预防死锁的发生。此外,内核级别的锁管理器也应提供死锁检测与恢复机制。 --- #### 监控与调优建议 - 使用数据库内置工具定期检查死锁日志,识别高频冲突事务。 - 对频繁更新的数据对象进行索引优化,减少全表扫描带来的锁竞争。 - 在高并发场景下,结合队列系统或异步处理机制缓解数据库压力。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值