4.5 并发技术5:死锁问题
程序员文章站
2022-05-22 11:20:27
...
1. 同一个goroutine中,使用同一个 channel 读写
package main
func main(){
ch:=make(chan int) //这就是在main程里面发生的死锁情况
ch<-6 // 这里会发生一直阻塞的情况,执行不到下面一句
<-ch
}
这是最简单的死锁情况
看运行结果
1. 2个 以上的go程中, 使用同一个 channel 通信。 读写channel 先于 go程创建。
package main
func main(){
ch:=make(chan int)
ch<-666 //这里一直阻塞,运行不到下面
go func (){
<-ch //这里虽然创建了子go程用来读出数据,但是上面会一直阻塞运行不到下面
}()
}
这里如果想不成为死锁那匿名函数go程就要放到ch<-666这条语句前面
3. 2个以上的go程中,使用多个 channel 通信。 A go 程 获取channel 1 的同时,尝试使用channel 2, 同一时刻,B go 程 获取channel 2 的同时,尝试使用channel 1
package main
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() { //匿名子go程
for {
select { //这里互相等对方造成死锁
case <-ch1: //这里ch1有数据读出才会执行下一句
ch2 <- 777
}
}
}()
for { //主go程
select {
case <-ch2 : //这里ch2有数据读出才会执行下一句
ch1 <- 999
}
}
}
第三种是互相等对方造成死锁
4.注意读写模式的锁定不要互相阻塞
- 隐形死锁:系统的两个或多个任务之间互相阻塞对方,形成事实上的死锁局面,然而只要有可运行的协程,编译器就不会显式地报死锁错误——这就是隐形死锁;
- 开发中真正可怕的不是显式的死锁,而是隐形死锁;
func main() {
var rwm09 sync.RWMutex
ch := make(chan int, 0)
//子协程负责写入
go func() {
//连锁都抢不到555...
rwm09.Lock()
ch <- 123
rwm09.Unlock()
}()
go func() {
//本协程负责读出
rwm09.RLock()
//只要读不到内容就永远阻塞
x := <- ch
fmt.Println("读到",x)
rwm09.RUnlock()
}()
for {
//通知垃圾回收器来清理垃圾(即使不叫也会定时清理)
runtime.GC()
}
}
上一篇: 【mysql】死锁-产生原因和解决方法
下一篇: 第三章 线程的同步与死锁