【问题标题】:deadlock on not buffered channel未缓冲通道上的死锁
【发布时间】:2021-08-15 04:10:57
【问题描述】:

我目前正在关注tour of go 教程并进入频道部分,因为我正在做一些测试,我发现了一个我很难理解的奇怪行为

以下代码产生死锁错误

package main

import "fmt"

func main() {
    c := make(chan string)
    c <- "test"
    fmt.Printf("%v", <- c)
}

但执行以下操作之一可以修复代码

使用缓冲通道:

package main

import "fmt"

func main() {
    c := make(chan string, 1)
    c <- "test"
    fmt.Printf("%v", <- c)
}

或将值设置到不同线程上的通道

package main

import "fmt"

func main() {
    c := make(chan string)
    go func(){c <- "test"}()
    fmt.Printf("%v", <- c)
}

第一版代码产生死锁的根本原因是什么?

【问题讨论】:

    标签: go channel


    【解决方案1】:

    只有在有另一个 goroutine 从该通道读取数据时,写入无缓冲通道才会成功。在第一种情况下,您只有一个 goroutine,即 main goroutine,它写入一个无缓冲的通道,并且没有其他 goroutine 可以从中读取,因此这是一个死锁。

    第二个有效,因为通道是缓冲的,通过填充缓冲区写入成功。没有读取的第二次写入将死锁。

    第三个有效,因为写入发生在一个单独的 goroutine 中,它一直等到第一个 goroutine 中的读取运行。

    【讨论】:

    • "第二个有效,因为通道被缓冲了,通过填充缓冲区写入成功。没有读取的第二个写入将死锁。"它没有,工作得很好
    • 第二次写入,在读取之前,将无限期阻塞。
    • 由于我的示例中缓冲区的大小,但不是因为该值从未被读取test
    • 你的问题中缓冲区的大小是1,但在你的测试中是2。把它改成1,就会死锁。
    • 我误会了,我以为你是说第二次写入后第二次会失败,因为值没有被消耗,而不是由于缓冲区的大小
    【解决方案2】:

    由于通道没有缓冲区,c &lt;- "test" 将阻塞,直到从 c 读取某些内容。由于读取器在写入之后出现,因此它永远不会到达读取和死锁。

    如果通道有缓冲区,c &lt;- "test" 会写入缓冲区,而不必等待读取器。然后读取器从通道缓冲区中读取。

    这都是因为读写器在同一个 goroutine 中,因此必须一个接一个地执行语句。如果读取器和写入器位于不同的 goroutine 中,则写入器 goroutine 可以阻塞,直到读取器 goroutine 读取为止。因此,通常不需要缓冲区。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-06
      • 2021-12-25
      • 2014-05-26
      • 2019-09-15
      • 1970-01-01
      • 2011-10-09
      • 1970-01-01
      相关资源
      最近更新 更多