死锁
死锁
死锁四大条件
- 互斥条件:资源在一个时间段内只能为一个进程使用,其他进程阻塞等待
- 保持与请求条件:进程在保持占有一个资源,又请求新资源
- 不可剥夺条件:进程占用的资源只能由该进程释放
- 循环等待条件:多个进程形成循环等待资源释放
死锁处理方式(根据死锁产生的前中后)
预防死锁
- 破坏死锁产生条件
避免死锁
- 银行家算法
- 加锁顺序
- 加锁时限
检测死锁
- 由操作系统实现死锁检测进程,若产生死锁,执行解除死锁
解除死锁
- 撤销进程法
- 进程回退法
go死锁场景
- 重复加锁(死锁,非 panic)
1 2 3 4 5 6
func main() { var mu sync.Mutex mu.Lock() mu.Lock() // 永远阻塞,Go 检测到所有 goroutine 都在睡眠时报: // fatal error: all goroutines are asleep - deadlock! }
- AB-BA 锁顺序死锁 ```go var muA, muB sync.Mutex
// goroutine 1 go func() { muA.Lock() time.Sleep(time.Millisecond) // 模拟执行 muB.Lock() // 等 goroutine 2 释放 muB defer muA.Unlock() defer muB.Unlock() }()
// goroutine 2 go func() { muB.Lock() time.Sleep(time.Millisecond) muA.Lock() // 等 goroutine 1 释放 muA defer muB.Unlock() defer muA.Unlock() }()
1
2
3
4
5
6
7
8
9
- channel 阻塞
```go
func main() {
ch := make(chan int)
ch <- 1 // 阻塞等接收者,但没有其他 goroutine
fmt.Println(<-ch)
// fatal error: all goroutines are asleep - deadlock!
}
- WaitGroup使用不当
select 缺少退出分支
- RWMutex 写锁中尝试读锁 ```go var rw sync.RWMutex
func main() { rw.Lock() // 获取写锁 rw.RLock() // 同一 goroutine 尝试读锁 → 永远阻塞 // 写锁持有时,读锁被阻塞;但写锁要等读锁完才释放 → 死锁 } ```
This post is licensed under CC BY 4.0 by the author.