死锁(Deadlock)是指两个或多个事务在持有资源的同时,又请求其他事务持有的资源,从而造成事务之间互相等待,且这种等待状态不会自动解除的情况。死锁通常发生在以下几种情况下:
1. 持有并请求(Hold and Wait)
一个事务已经持有一个资源的锁,同时又请求另一个资源的锁,而该资源正被另一个事务持有。由于两个事务都在等待对方释放资源,导致死锁。
示例:
- 事务T1持有资源A的锁,并请求资源B的锁。
- 事务T2持有资源B的锁,并请求资源A的锁。
- 结果:T1等待T2释放B,T2等待T1释放A,形成死锁。
2. 非抢占(No Preemption)
事务所持有的资源锁不能被强制剥夺,必须由持有资源的事务自行释放。如果事务不主动释放资源,其他事务将无法获得这些资源,导致死锁。
3. 循环等待(Circular Wait)
存在一个事务等待链,事务之间相互等待资源,形成一个循环等待的状态。
示例:
- 事务T1等待T2释放资源A。
- 事务T2等待T3释放资源B。
- 事务T3等待T1释放资源C。
- 结果:T1、T2、T3之间形成循环等待,导致死锁。
4. 资源不足(Resource Insufficiency)
系统中可用的资源不足以满足所有事务的需求,导致事务之间相互等待资源,可能引发死锁。
如何避免死锁
-
资源分配策略:
- 预防策略:严格控制资源分配顺序,避免循环等待。例如,要求所有事务按照同样的顺序请求资源。
- 避免策略:在事务开始时,预先分配所有需要的资源。如果无法分配所有资源,则不开始该事务。
-
检测和解除死锁:
- 死锁检测:系统定期检查是否存在死锁,通常通过构建等待图来检测循环等待。若发现死锁,则选择回滚一个或多个事务以解除死锁。
- 死锁解除:当检测到死锁后,通过回滚(撤销)某些事务来打破循环等待,从而解除死锁。
-
资源抢占:
- 超时机制:设置事务等待资源的最大时间,超过时间后自动回滚该事务,从而避免长期的循环等待。
具体示例
假设有两个事务T1和T2,以及资源A和B:
-
死锁场景:
- T1锁定资源A,然后请求锁定资源B。
- T2锁定资源B,然后请求锁定资源A。
- 结果:T1等待T2释放B,T2等待T1释放A,形成死锁。
-
避免死锁的资源分配策略:
- 要求事务按相同顺序请求资源(例如,先请求资源A,再请求资源B),这样可以避免循环等待。
总结
死锁是并发控制中的一个重要问题,通过合理的资源分配策略、死锁检测和解除机制,以及资源抢占策略,可以有效地避免和处理死锁,保证系统的稳定性和并发事务的正确执行。