背景介绍
在做操作系统的测试题,在做题的过程中发现有很多地方涉及到了关于死锁的知识点。就回归课本来自己琢磨一下死锁。下面就把我琢磨的成果分享给大家。
死锁的前提
- 并发编程:死锁是在并发环境下发生的,因此了解并发编程的基本概念和机制是理解死锁的前提。包括多线程、多进程、资源竞争等概念。
- 资源竞争:死锁是由于资源竞争而产生的,因此了解资源的概念和不同类型的资源是理解死锁的前提。包括共享资源和独占资源等。
死锁的概念
死锁是指在并发环境中,两个或多个进程或线程因为竞争有限的资源而无法继续执行的状态。这种状态下,每个进程或线程都在等待其他进程或线程所持有的资源,形成了一个相互等待的循环。
死锁的分类
死锁可以分为资源死锁和进程死锁。资源死锁是指多个进程或线程竞争有限的资源而导致的死锁,而进程死锁是指多个进程之间因为相互等待对方释放资源而导致的死锁。
死锁的产生
原因
竞争共享资源的同时分配资源的顺序不当
条件
「 互斥条件 」:指一个进程在访问资源的过程中,其他进程不能访问该资源。如果一个资源正在被访问时,有其他进程也提出对该资源的访问请求,必须把请求该资源的 进程阻塞起来,直到资源被进程释放 。
「 请求和保持条件」:进程已经保持了至少一个资源,又提出了新的资源要求,而新的请求已经被其他进程占有,此时进程阻塞,但有对已经获得的资源保持不放,使得其他进程无法使用被保持的资源。
「不剥夺条件 」:进程已经获得的资源不能被剥夺,只能由进程自己释放。
「 环路等待条件 」:在发生死锁时,必然存在一个进程申请资源的环形链。
- 每个资源类用一个方框表示,方框中的原点表示此资源类中的各个资源;
- 每个进程用一个圆圈来表示,用有向边表示进程申请资源和资源分配情况。
- 约定方框→圆圈表示资源分配,圆圈→方框表示申请资源。
- 这种情况下,图3-6 发生了死锁,而图3-7没有发生死锁。
死锁的解决
预防
死锁预防是通过破坏死锁产生的四个条件来避免死锁的发生。常见的预防措施包括资源分配策略、资源的有序分配、避免占有并等待、资源剥夺和循环等待的预防。
避免
死锁避免是在资源分配过程中,通过动态地检测和避免可能导致死锁的资源分配序列,来避免死锁的发生。常见的避免方法包括安全序列算法、银行家算法和资源分配图算法。死锁的避免是把系统的资源分配状态分为安全状态和不安全状态,只要资源分配使系统资源分配状态处于安全状态,死锁就不会发生死锁。
1.安全状态:系统按照顺序为每个进程分配资源,确保每个进程的资源分配和执行顺利完成,不会发生死锁时,称系统处于安全状态。
2.不安全状态:系统不存在安全状态这样的安全序列,则是不安全状态,不安全状态不一定是死锁状态。但是可能会发生死锁状态。
检测与恢复
死锁检测是通过周期性地检测系统资源分配情况,来判断系统是否发生死锁。一旦检测到死锁,可以采取恢复措施,如剥夺资源、回滚进程或线程等。
死锁的实现
import threading # 创建两个资源 resource1 = threading.Lock() resource2 = threading.Lock() # 线程1的执行函数 def thread1_func(): print("Thread 1: Acquiring resource 1") resource1.acquire() print("Thread 1: Acquired resource 1") print("Thread 1: Acquiring resource 2") resource2.acquire() print("Thread 1: Acquired resource 2") # 执行一些操作... resource2.release() print("Thread 1: Released resource 2") resource1.release() print("Thread 1: Released resource 1") # 线程2的执行函数 def thread2_func(): print("Thread 2: Acquiring resource 2") resource2.acquire() print("Thread 2: Acquired resource 2") print("Thread 2: Acquiring resource 1") resource1.acquire() print("Thread 2: Acquired resource 1") # 执行一些操作... resource1.release() print("Thread 2: Released resource 1") resource2.release() print("Thread 2: Released resource 2") # 创建两个线程 thread1 = threading.Thread(target=thread1_func) thread2 = threading.Thread(target=thread2_func) # 启动线程 thread1.start() thread2.start() # 等待线程执行完毕 thread1.join() thread2.join()
在上述代码中,我们创建了两个资源 resource1 和 resource2,并在两个线程中分别获取这两个资源。然而,线程1首先获取了 resource1,然后尝试获取 resource2,而线程2则相反,首先获取了 resource2,然后尝试获取 resource1。由于资源的互斥条件,线程1无法继续执行直到释放 resource2,而线程2也无法继续执行直到释放 resource1,从而形成了一个死锁的情况。
总结提升
操作系统死锁是指在并发环境下,由于资源竞争而导致的进程或线程无法继续执行的状态。死锁的产生需要满足一定的条件,可以通过预防、避免、检测和解决等策略来处理死锁问题。了解和掌握死锁相关知识对于设计和优化并发系统非常重要。
需要注意的是,死锁并不是必然发生的,它取决于资源的获取顺序和调度器的调度策略。在上述代码中,如果线程1先获取 resource2,线程2先获取 resource1,则不会发生死锁。因此,死锁是一个非确定性的问题,需要通过合理的资源分配和调度策略来避免。