go的几种死锁情况分析

本文详细介绍了Go语言中四种常见的死锁情况:1) 同一goroutine中对同一channel的读写;2) 多个goroutine中先创建channel再进行通信;3) 多个goroutine互相等待不同channel;4) channel与读写锁、互斥锁交叉混用导致的隐形死锁。通过案例分析,帮助理解并避免死锁问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值