🔒 死锁 (Deadlock) 概念、原因及解决方法
🧠 一、死锁的概念
死锁是指两个或多个进程在相互等待对方所持有的资源时,发生的一种永久性阻塞状态。
- 每个进程都在等待其他进程释放资源,导致系统无法继续执行。
- 如果没有外部干预,死锁情况将无限期持续。
🧐 二、死锁的四个必要条件 (同时满足以下四个条件才会发生死锁)
根据 Coffman 提出的死锁四要素:
-
互斥 (Mutual Exclusion)
- 某些资源一次只能由一个进程使用。
- 如打印机、数据库写操作等。
-
占有并等待 (Hold and Wait)
- 一个进程已持有某些资源,并且正在等待其他资源,而这些资源正被其他进程占用。
-
不可剥夺 (No Preemption)
- 已分配的资源不能被强行回收,只能由持有资源的进程主动释放。
-
循环等待 (Circular Wait)
- 存在一组进程,每个进程都在等待下一个进程所持有的资源。
🚨 死锁发生的本质:系统未对资源访问进行有效的协调和控制。
⚠️ 三、死锁产生的常见原因
-
资源竞争
- 多个进程同时请求共享资源,且系统未妥善协调。
-
资源分配不合理
- 资源未能按需求一次性分配,导致进程占用部分资源又请求新资源。
-
不正确的锁机制
- 锁使用不当,导致资源被不必要的持有。
-
嵌套锁
- 进程在持有资源 A 的同时,又请求资源 B,其他进程反向持有 B 再请求 A,形成死锁。
🛡️ 四、死锁的解决方法
🔍 1. 预防 (Prevention)
- 破坏死锁的四个条件之一,防止死锁发生。
- 常用方法:
- 破坏占有并等待:在请求资源前,必须一次性申请完所需资源。
- 破坏循环等待:对资源编号,按序申请资源。
示例:银行家算法 (Banker's Algorithm) —— 核心思想是安全状态判断,防止系统进入死锁状态。
🧪 2. 避免 (Avoidance)
- 系统动态检测可能导致死锁的情况,避免进入死锁状态。
- 常用方法:
- 每次资源申请时,判断分配后是否仍处于“安全状态”。
- 如果资源分配会导致死锁,则拒绝该请求。
🖥️ 3. 检测 (Detection)
- 允许死锁发生,并在发生时检测并解除。
- 死锁检测算法:
- 资源分配图算法 (用于单一资源)
- 等待图算法 (用于多资源)
🔄 4. 解除 (Recovery)
- 检测到死锁后,采取相应的措施来解除死锁。
- 常用方法:
- 终止进程:选择一个或多个进程终止以打破死锁。
- 回滚 (Rollback):将进程回退到之前的某个安全状态。
- 资源抢占:强行从某些进程中回收资源,重新分配。
📋 五、死锁示例 (代码演示)
C 语言中的死锁代码示例:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock1;
pthread_mutex_t lock2;
void* thread1(void* arg) {
pthread_mutex_lock(&lock1);
printf("线程 1 锁住 lock1\n");
sleep(1); // 模拟线程 1 在等待时的延迟
pthread_mutex_lock(&lock2);
printf("线程 1 锁住 lock2\n");
pthread_mutex_unlock(&lock2);
pthread_mutex_unlock(&lock1);
return NULL;
}
void* thread2(void* arg) {
pthread_mutex_lock(&lock2);
printf("线程 2 锁住 lock2\n");
sleep(1); // 模拟线程 2 在等待时的延迟
pthread_mutex_lock(&lock1);
printf("线程 2 锁住 lock1\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock1, NULL);
pthread_mutex_init(&lock2, NULL);
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&lock1);
pthread_mutex_destroy(&lock2);
return 0;
}
🔎 解释
- 线程 1 锁住
lock1后等待lock2; - 线程 2 锁住
lock2后等待lock1; - 由于两个线程都在等待对方持有的锁,导致死锁发生。
🚀 六、最佳实践 (避免死锁的技巧)
✅ 尽量减少资源持有时间,及时释放不再使用的资源;
✅ 尽可能一次性申请所需资源,避免占有并等待;
✅ 遵循统一的资源申请顺序,破坏循环等待条件;
✅ 利用超时机制,避免长时间阻塞;
✅ 使用更高级的锁机制(如读写锁、信号量)来优化资源争用。
🎯 总结
死锁是一种严重影响系统性能的问题,理解其原理、成因和解决方法是掌握操作系统的重要一环。

8019

被折叠的 条评论
为什么被折叠?



