Post

死锁

死锁

死锁四大条件

  • 互斥条件:资源在一个时间段内只能为一个进程使用,其他进程阻塞等待
  • 保持与请求条件:进程在保持占有一个资源,又请求新资源
  • 不可剥夺条件:进程占用的资源只能由该进程释放
  • 循环等待条件:多个进程形成循环等待资源释放

死锁处理方式(根据死锁产生的前中后)

预防死锁

  • 破坏死锁产生条件

避免死锁

  • 银行家算法
  • 加锁顺序
  • 加锁时限

检测死锁

  • 由操作系统实现死锁检测进程,若产生死锁,执行解除死锁

解除死锁

  • 撤销进程法
  • 进程回退法

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.