死锁
死锁条件
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁的方法
那么避免死锁问题就只需要破环其中一个条件就可以,最常见的并且可行的就是使用资源有序分配法,来破环环路等待条件。
代码示例:
package main
import (
"fmt"
"sync"
"time"
)
var A = sync.Mutex{}
var B = sync.Mutex{}
// goroutineA 协程函数 A
func goroutineA() {
fmt.Printf("thread A waiting get ResourceA \n")
A.Lock()
fmt.Printf("thread A got ResourceA \n")
time.Sleep(1 * time.Second)
fmt.Printf("thread A waiting get ResourceB \n")
B.Lock()
fmt.Printf("thread A got ResourceB \n")
A.Unlock()
B.Unlock()
return
}
// goroutineB 协程函数 B
func goroutineB() {
fmt.Printf("thread B waiting get ResourceB \n")
B.Lock()
fmt.Printf("thread B got ResourceB \n")
time.Sleep(1 * time.Second)
fmt.Printf("thread B waiting get ResourceA \n")
A.Lock()
fmt.Printf("thread B got ResourceA \n")
A.Unlock()
B.Unlock()
return
}
// goroutineBSolved 协程函数 B
func goroutineBSolved() {
fmt.Printf("thread B waiting get ResourceA \n")
A.Lock()
fmt.Printf("thread B got ResourceA \n")
time.Sleep(1 * time.Second)
fmt.Printf("thread B waiting get ResourceB \n")
B.Lock()
fmt.Printf("thread B got ResourceB \n")
A.Unlock()
B.Unlock()
return
}
资源循环引用
//创建两个协程
go func() {
goroutineA()
fmt.Println("A finish")
}()
go func() {
goroutineB()
fmt.Println("B finish")
}()
<-time.After(3 * 60 * time.Second)
return
死锁:
thread A waiting get ResourceA
thread A got ResourceA
thread B waiting get ResourceB
thread B got ResourceB
thread B waiting get ResourceA
thread A waiting get ResourceB
资源顺序引用,破解循环
//创建两个协程
go func() {
goroutineA()
fmt.Println("A finish")
}()
go func(){
goroutineBSolved()
fmt.Println("B finish")
}()
不会死锁:
thread A waiting get ResourceA
thread A got ResourceA
thread B waiting get ResourceA
thread A waiting get ResourceB
thread A got ResourceB
A finish
thread B got ResourceA
thread B waiting get ResourceB
thread B got ResourceB
B finish