|版权声明:本文为博主原创文章,未经博主允许不得转载。博客地址: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()
    }
}

这是一种隐形的死锁,我们来看一下结果这里写图片描述
注意这几种的死锁情况