|版权声明:本文为博主原创文章,未经博主允许不得转载。博客地址:https://blog.csdn.net/sgsgy5
在go语言中用channel通信稍不注意就会发生死锁情况,下面我们来看一下几种常见的死锁情况
第一种:同一个goroutine中,使用同一个 channel 读写。
package main
func main(){
ch:=make(chan int) //这就是在main程里面发生的死锁情况
ch<-6 // 这里会发生一直阻塞的情况,执行不到下面一句
<-ch
}
这是最简单的死锁情况
看运行结果
第二种:2个 以上的go程中, 使用同一个 channel 通信。 读写channel 先于 go程创建。
package main
func main(){
ch:=make(chan int)
ch<-666 //这里一直阻塞,运行不到下面
go func (){
<-ch //这里虽然创建了子go程用来读出数据,但是上面会一直阻塞运行不到下面
}()
}
这里如果想不成为死锁那匿名函数go程就要放到ch<-666这条语句前面
看运行结果
还是同样的错误,死锁。
第三种: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
}
}
}
第三种是互相等对方造成死锁
第四种: 在go语言中, channel 和 读写锁、互斥锁 尽量避免交叉混用。——“隐形死锁”。如果必须使用。推荐借助“条件变量”
package main
import (
"runtime"
"math/rand"
"time"
"fmt"
"sync"
)
// 使用读写锁
var rwMutex2 sync.RWMutex
func readGo2(idx int, in <-chan int) { // 读go程
for {
time.Sleep(time.Millisecond * 500) // 放大实验现象// 一个go程可以读 无限 次。
rwMutex2.RLock() // 读模式加 读写锁
num := <-in // 从 公共的 channel 中获取数据
fmt.Printf("%dth 读 go程,读到:%d\n", idx, num)
rwMutex2.RUnlock() // 解锁 读写锁
}
}
func writeGo2(idx int, out chan<- int) {
for { // 一个go程可以写 无限 次。
// 生产一个随机数
num := rand.Intn(500)
rwMutex2.Lock() // 写模式加 读写锁
out <- num
fmt.Printf("-----%dth 写 go程,写入:%d\n", idx, num)
rwMutex2.Unlock() // 解锁 读写锁
//time.Sleep(time.Millisecond * 200) // 放大实验现象
}
}
func main() {
// 播种随机数种子。
rand.Seed(time.Now().UnixNano())
// 创建 模拟公共区的 channel
ch := make(chan int, 5)
for i:=0; i<5; i++ { // 同时创建 N 个 读go程
go readGo2(i+1, ch)
}
for i:=0; i<5; i++ { // 同时创建 N 个 写go程
go writeGo2(i+1, ch)
}
for { // 防止 主 go 程 退出
runtime.GC()
}
}
这是一种隐形的死锁,我们来看一下结果
注意这几种的死锁情况