详解Golang并发操作中常见的死锁情形

 更新时间:2021年09月01日 08:52:15   作者:ReganYue  
在Go的协程里面死锁通常就是永久阻塞了,本文主要介绍了Golang并发操作中常见的死锁情形,具有一定的参考价值,感兴趣的可以了解一下

什么是死锁,在Go的协程里面死锁通常就是永久阻塞了,你拿着我的东西,要我先给你然后再给我,我拿着你的东西又让你先给我,不然就不给你。我俩都这么想,这事就解决不了了。

第一种情形:无缓存能力的管道,自己写完自己读

先上代码:

func main() {
    ch := make(chan int, 0)
​
    ch <- 666
    x := <- ch
    fmt.Println(x)
}

我们可以看到这是一个没有缓存能力的管道,然后往里面写666,然后就去管道里面读。这样肯定会出现问题啊!一个无缓存能力的管道,没有人读,你也写不了,没有人写,你也读不了,这正是一种死锁!

fatal error: all goroutines are asleep - deadlock!

解决办法很简单,开辟两条协程,一条协程写,一条协程读。

第二种情形:协程来晚了

func main() {
    ch := make(chan int,0)
    ch <- 666
    go func() {
        <- ch
    }()
}

我们可以看到,这条协程开辟在将数字写入到管道之后,因为没有人读,管道就不能写,然后写入管道的操作就一直阻塞。这时候你就有疑惑了,不是开辟了一条协程在读吗?但是那条协程开辟在写入管道之后,如果不能写入管道,就开辟不了协程。

第三种情形:管道读写时,相互要求对方先读/写

如果相互要求对方先读/写,自己再读/写,就会造成死锁。

func main() {
    chHusband := make(chan int,0)
    chWife := make(chan int,0)
​
    go func() {
        select {
        case <- chHusband:
            chWife<-888
        }
    }()
​
    select {
        case <- chWife:
            chHusband <- 888
    }
}

先来看看老婆协程,chWife只要能读出来,也就是老婆有钱,就给老公发个八百八十八的大红包。

再看看老公的协程,一看不得了,咋啦?老公也说只要他有钱就给老婆包个八百八十八的大红包。

两个人都说自己没钱,老公也给老婆发不了红包,老婆也给老公发不了红包,这就是死锁!

第四种情形:读写锁相互阻塞,形成隐形死锁

先来看一看代码:

func main() {
    var rmw09 sync.RWMutex
    ch := make(chan int,0)
​
    go func() {
        rmw09.Lock()
        ch <- 123
        rmw09.Unlock()
    }()
​
    go func() {
        rmw09.RLock()
        x := <- ch
        fmt.Println("读到",x)
        rmw09.RUnlock()
    }()
​
    for {
        runtime.GC()
    }
}

这两条协程,如果第一条协程先抢到了只写锁,另一条协程就不能抢只读锁了,那么因为另外一条协程没有读,所以第一条协程就写不进。

如果第二条协程先抢到了只读锁,另一条协程就不能抢只写锁了,那么因为另外一条协程没有写,所以第二条协程就读不到。

到此这篇关于详解Golang并发操作中常见的死锁情形的文章就介绍到这了,更多相关Golang 并发死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go中的nil切片和空切片区别详解

    Go中的nil切片和空切片区别详解

    这篇文章主要介绍了Go中的nil切片和空切片区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • go语言interface接口继承多态示例及定义解析

    go语言interface接口继承多态示例及定义解析

    这篇文章主要为大家介绍了go语言interface接口继承多态示例及定义解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • Golang分布式锁简单案例实现流程

    Golang分布式锁简单案例实现流程

    分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源时,需要通过一些互斥手段来防止彼此之间的干扰以保证一致性,在这种情况下,就需要使用分布式锁了
    2022-12-12
  • golang读取http的body时遇到的坑及解决

    golang读取http的body时遇到的坑及解决

    这篇文章主要介绍了golang读取http的body时遇到的坑及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • goland配置自动注释的实现

    goland配置自动注释的实现

    本文主要介绍了goland配置自动注释的实现,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • Golang程序漏洞检测器govulncheck的安装和使用

    Golang程序漏洞检测器govulncheck的安装和使用

    govulncheck 是一个命令行工具,可以帮助 Golang 开发者快速找到项目代码和依赖的模块中的安全漏洞,该工具可以分析源代码和二进制文件,识别代码中对这些漏洞的任何直接或间接调用,本文就给大家介绍一下govulncheck安装和使用,需要的朋友可以参考下
    2023-09-09
  • GO语言实现批量压缩图片和水印

    GO语言实现批量压缩图片和水印

    这篇文章主要介绍了GO语言实现批量压缩图片和水印,主要用到了github.com/nfnt/resize这个第三方库,仅仅支持JPG图片格式,有相同需求的小伙伴参考下吧。
    2015-03-03
  • Go语言图片处理和生成缩略图的方法

    Go语言图片处理和生成缩略图的方法

    这篇文章主要介绍了Go语言图片处理和生成缩略图的方法,涉及Go语言针对图片操作的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • 使用Go语言实现一个简单的无界资源池

    使用Go语言实现一个简单的无界资源池

    本文我们希望通过go语言实现一个简单的资源池,而这个资源池的资源包括但不限于数据库连接池,线程池,协程池,网络连接池,只要这些资源实现我们指定的关闭方法,则都可以通过我们封装的资源池进行统一管理,文中通过代码示例给大家介绍的非常详细,需要的朋友可以参考下
    2024-05-05
  • Go语言基础函数包的使用学习

    Go语言基础函数包的使用学习

    本文通过一个实现加减乘除运算的小程序来介绍go函数的使用,以及使用函数的注意事项,并引出了对包的了解和使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05

最新评论