卡码笔记
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
首页
计算机基础
C++
Java
面经
笔记广场 (opens new window)
代码随想录 (opens new window)
  • 操作系统

    • 基础概念

    • 进程与线程

    • 中断与异常

    • 同步与互斥

    • 死锁

      • 什么是死锁?如何避免死锁?
      • 产生死锁的原因有什么?
        • 简要回答
        • 专业回答
        • 代码示例
        • 知识拓展
      • 处理死锁的基本方法有什么?
      • 简述下银行家算法
    • 内存管理

    • I/O 与设备管理

    • 其他

  • 网络

  • 数据库

# 产生死锁的原因有什么?

# 简要回答

死锁是指多个进程因竞争资源而相互等待的僵局。

必须同时满足四个条件:互斥、持有并等待、不可抢占、循环等待

# 专业回答

死锁产生的四个必要条件

互斥条件:资源是独占的,一次只能被一个进程使用,

持有并等待:进程已持有资源,同时等待其他资源,

不可抢占:进程持有的资源不能被强制剥夺,

循环等待:存在进程-资源的循环等待链

具体原因分析

资源竞争:多进程争用有限资源, 推进顺序不当:进程执行顺序不合理, 资源分配策略问题:缺乏预防和避免机制, 程序设计缺陷:未考虑资源获取顺序

# 代码示例

中断处理示示例

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex mutex1, mutex2;

// 线程1:先锁mutex1,再锁mutex2
void thread1_func() {
    std::unique_lock<std::mutex> lock1(mutex1);
    std::cout << "线程1获得锁1,等待锁2..." << std::endl;

    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 增加死锁概率

    std::unique_lock<std::mutex> lock2(mutex2);
    std::cout << "线程1获得锁1和锁2" << std::endl;
}

// 线程2:先锁mutex2,再锁mutex1
void thread2_func() {
    std::unique_lock<std::mutex> lock1(mutex2);
    std::cout << "线程2获得锁2,等待锁1..." << std::endl;

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    std::unique_lock<std::mutex> lock2(mutex1);
    std::cout << "线程2获得锁1和锁2" << std::endl;
}

int main() {
    std::thread t1(thread1_func);
    std::thread t2(thread2_func);

    t1.join();
    t2.join();

    std::cout << "程序结束" << std::endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

解锁方案实例

// 解决方案示例:按固定顺序获取锁
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mutex1, mutex2;

// 解决方案:统一获取锁的顺序
void safe_thread1_func() {
    // 总是先获取mutex1,再获取mutex2
    std::lock(mutex1, mutex2); // 同时锁定,避免死锁
    std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);

    std::cout << "线程1安全地获得两把锁" << std::endl;
}

void safe_thread2_func() {
    // 同样先获取mutex1,再获取mutex2
    std::lock(mutex1, mutex2);
    std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);

    std::cout << "线程2安全地获得两把锁" << std::endl;
}

int main() {
    std::thread t1(safe_thread1_func);
    std::thread t2(safe_thread2_func);

    t1.join();
    t2.join();

    std::cout << "安全结束" << std::endl;
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 知识拓展

死锁处理策略

1.预防:破坏四个必要条件之一2.避免:银行家算法,安全序列检测3.检测:资源分配图检测环路 4.恢复:终止进程或剥夺资源

常见死锁场景

数据库:事务锁定顺序不一致,操作系统:打印机和磁带机分配, 多线程:锁顺序不一致, 分布式系统:多个节点相互等待

资源分配图

圆形:进程, 方形:资源, 资源→进程:分配边, 进程→资源:请求边, 检测环路判断死锁,

  • 知识图解

image

  • 适用场景

数据库系统

事务A锁定行1等待行2

事务B锁定行2等待行1

解决方案:两阶段锁定协议

操作系统资源管理

进程1持有打印机请求扫描仪

进程2持有扫描仪请求打印机

解决方案:资源有序分配

多线程编程

线程A:lock(m1)→lock(m2)

线程B:lock(m2)→lock(m1)

解决方案:锁层次结构

  • 面试官很能追问

Q1:如何避免死锁?

A1: 预防:破坏四个条件

破坏互斥:某些资源可共享(如只读文件)

破坏持有并等待:一次申请所有资源

破坏不可抢占:允许资源抢占

破坏循环等待:资源按序申请

避免:银行家算法,预判是否安全

检测与恢复:定期检测环路,强制剥夺资源

Q2:银行家算法原理是什么?

A2:模仿银行家放贷,进程声明最大需求,系统检查分配后是否仍能找到一个安全序列(所有进程都能完成)。

需要四个数据结构:可用资源、最大需求、已分配、需求矩阵。

Q3:实际开发中如何预防死锁?

A3: 锁顺序:所有线程按相同顺序获取锁

锁超时:尝试获取锁设置超时

锁粒度:尽量减小锁范围

无锁编程:使用原子操作或无锁数据结构

层级锁:定义锁的获取层级

Q4:死锁和活锁有什么区别?

A4: 死锁:进程阻塞,什么都不做

活锁:进程在运行,但无法进展(如两人相向而行,不断让路)

饥饿:进程长期得不到资源,但有进展可能

Last Updated: 3/10/2026, 6:08:48 PM

← 什么是死锁?如何避免死锁? 处理死锁的基本方法有什么? →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪