网站建设价格专注制作网站设计,网站排名优化软件有哪些,营销推广的主要方式,商机创业网2021创业在 Linux 中#xff0c;死锁#xff08;Deadlock#xff09; 是指多个进程或线程因为竞争资源而相互等待#xff0c;导致所有相关进程或线程都无法继续执行的状态。死锁是一种严重的系统问题#xff0c;会导致系统资源浪费#xff0c;甚至系统崩溃。 死锁的定义 死锁是指… 在 Linux 中死锁Deadlock 是指多个进程或线程因为竞争资源而相互等待导致所有相关进程或线程都无法继续执行的状态。死锁是一种严重的系统问题会导致系统资源浪费甚至系统崩溃。 死锁的定义 死锁是指两个或多个进程或线程在执行过程中因为争夺资源而造成的一种互相等待的现象。如果没有外部干预这些进程或线程将永远无法继续执行。 死锁的四个必要条件 死锁的发生需要同时满足以下四个条件称为 Coffman 条件 互斥条件Mutual Exclusion 资源一次只能被一个进程或线程占用。 例如锁如互斥锁就是一种互斥资源。 占有并等待Hold and Wait 进程或线程持有至少一个资源同时等待获取其他被占用的资源。 非抢占条件No Preemption 已分配给进程或线程的资源不能被强制剥夺必须由其自行释放。 循环等待条件Circular Wait 存在一个进程或线程的循环链每个进程或线程都在等待下一个进程或线程所占用的资源。 只有当这四个条件同时满足时死锁才会发生。 死锁的示例 以下是一个典型的死锁示例 #include pthread.h
#include stdio.hpthread_mutex_t mutexA PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutexB PTHREAD_MUTEX_INITIALIZER;void* thread1_func(void* arg) {pthread_mutex_lock(mutexA); // 线程1持有mutexAsleep(1); // 模拟一些操作pthread_mutex_lock(mutexB); // 线程1尝试获取mutexBprintf(Thread 1 is running.\n);pthread_mutex_unlock(mutexB);pthread_mutex_unlock(mutexA);return NULL;
}void* thread2_func(void* arg) {pthread_mutex_lock(mutexB); // 线程2持有mutexBsleep(1); // 模拟一些操作pthread_mutex_lock(mutexA); // 线程2尝试获取mutexAprintf(Thread 2 is running.\n);pthread_mutex_unlock(mutexA);pthread_mutex_unlock(mutexB);return NULL;
}int main() {pthread_t tid1, tid2;pthread_create(tid1, NULL, thread1_func, NULL);pthread_create(tid2, NULL, thread2_func, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);return 0;
} 线程1持有 mutexA 并等待 mutexB。 线程2持有 mutexB 并等待 mutexA。 两个线程互相等待导致死锁。 死锁的影响 资源浪费死锁会导致相关进程或线程无法继续执行占用系统资源。 系统崩溃如果死锁涉及关键资源可能导致整个系统无法正常运行。 难以调试死锁通常难以复现和调试尤其是在复杂的多线程程序中。 如何避免死锁 锁顺序确保所有线程以相同的顺序获取锁。 超时机制为锁操作设置超时如 pthread_mutex_timedlock避免无限等待。 避免嵌套锁尽量减少锁的嵌套使用。 死锁检测使用工具或算法检测死锁并采取措施。 资源分配策略使用资源分配算法如银行家算法避免死锁。 死锁检测与恢复 检测 使用工具如 gdb、valgrind分析程序运行状态。 实现死锁检测算法如图的环路检测。 恢复 强制终止一个或多个进程或线程。 回滚操作释放资源并重新分配。 线程阻塞 在 Linux 中死锁和阻塞是两个不同的概念尽管它们都与资源的竞争和等待有关但它们的表现和原因有显著区别 阻塞Blocking 定义阻塞是指一个进程或线程因为等待某个资源如锁、I/O 操作、信号量等而暂时无法继续执行进入等待状态。 原因 等待获取锁如互斥锁、读写锁。 等待 I/O 操作完成如读取文件、网络数据。 等待信号量或其他同步机制。 特点 阻塞是暂时的一旦资源可用进程或线程会被唤醒并继续执行。 阻塞是正常的同步机制用于协调多个进程或线程对共享资源的访问。 阻塞不会导致系统无法运行只是当前任务暂时停止。 示例 pthread_mutex_lock(mutex); // 如果锁被其他线程持有当前线程会阻塞
// 临界区代码
pthread_mutex_unlock(mutex); 区别总结 总之阻塞是正常的同步行为而死锁是需要避免的系统错误。 线程饥饿 一个线程持有锁一直不释放其他线程一直在等待这个锁这种情况不满足锁的四个必要条件算是死锁吗 比如如果一个线程持有锁后进入死循环且其他线程尝试获取该锁。 具体过程 线程 A 持有锁后进入死循环永远不会释放锁。 线程 B 尝试获取该锁但由于锁被线程 A 持有线程 B 会一直阻塞等待。 如果还有其他线程也尝试获取该锁它们同样会阻塞等待。 最终这些线程会因为无法获取锁而永久阻塞 示例代码如下 #include pthread.h
#include stdio.hpthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;void* thread_func(void* arg) {pthread_mutex_lock(mutex); // 线程 A 获取锁while (1) {// 死循环永远不会释放锁}pthread_mutex_unlock(mutex); // 这行代码永远不会执行return NULL;
}int main() {pthread_t tid;pthread_create(tid, NULL, thread_func, NULL);pthread_mutex_lock(mutex); // 主线程尝试获取锁会一直阻塞printf(This will never be printed.\n);pthread_mutex_unlock(mutex);pthread_join(tid, NULL);return 0;
} 线程 A 获取锁后进入死循环永远不会释放锁。 主线程尝试获取锁时会被阻塞 这种情况下虽然不满足死锁的四个必要条件但它确实会导致类似死锁的现象通常称为**资源饥饿Resource Starvation或活锁Livelock**的一种表现。下面详细分析 1. 这种情况的特点 一个线程持有锁后一直不释放。 其他线程因为无法获取锁而一直等待。 不满足死锁的四个必要条件特别是循环等待条件因为没有多个线程相互等待。 2. 为什么不是死锁 死锁的四个必要条件之一是循环等待即存在一个进程或线程的循环链每个进程或线程都在等待下一个进程或线程所占用的资源。而在你的描述中 只有一个线程持有锁其他线程在等待这个锁。 没有形成循环等待链因此不满足死锁的定义。 3. 这种情况的名称 这种情况通常被称为资源饥饿Resource Starvation 一个线程独占资源如锁导致其他线程无法获取资源从而无法继续执行。 资源饥饿不一定是死锁但它会导致系统性能下降或部分功能失效。 总结下线程饥饿和死锁的区别 比较明显的现象就是线程饥饿时通常会有部分线程还能执行但是死锁时涉及到的所有线程都无法执行。 更多参考 五、面试官你讲一下线程死锁、饥饿和死循环的区别以及死锁的处理 我滔滔不绝...._死锁和循环依赖的区别-CSDN博客 常见问题 死锁、资源饥饿、CPU飙高、内存泄漏、内存溢出、栈溢出