为了账号安全,请及时绑定邮箱和手机立即绑定

即使通道关闭,go 例程也会死锁

即使通道关闭,go 例程也会死锁

Go
MMTTMM 2021-08-16 19:16:52
我有一个列表,其中包含一个从中弹出元素的函数,以及另一个“接收”弹出元素的函数。我认为在接收器之后关闭会关闭通道,但是在到达那里之前程序似乎已经死锁了。这样做的最佳方法是什么?我是否应该有另一个通道来检测流行音乐何时完成?func pop(list *[]int, c chan int) {    if len(*list) != 0 {        result := (*list)[0]        *list = (*list)[1:]        fmt.Println("about to send ", result)        c <- result    } else {        return    }}func receiver(c chan int) {    result := <-c    fmt.Println("received ", result)}var list = []int{1, 2, 3}func main() {    fmt.Println("Main")    c := make(chan int)    go pop(&list, c)    go pop(&list, c)    for len(list) > 0 {        receiver(c)    }    close(c) //Dosen't seem to have any effect    fmt.Println("done")}
查看完整描述

1 回答

?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

代码有很多问题,让我们看看。

  1. 您的pop函数在访问切片时不会锁定,因此这就是数据竞争。

  2. for len(list) > 0 {} 是数据竞争,因为您正在访问列表,同时在其他 2 个 goroutine 中修改它。

  3. for len(list) > 0 {} 永远不会返回,因为您的列表中有 3 个项目,但您只调用了两次 pop。

  4. receiver(c) 由于 #3 导致的错误,它尝试从通道读取但没有写入任何内容。

一种方法是使用一个写入器 ( pop) 和多个读取器 ( receiver):

func pop(list *[]int, c chan int, done chan bool) {

    for len(*list) != 0 {

        result := (*list)[0]

        *list = (*list)[1:]

        fmt.Println("about to send ", result)

        c <- result

    }

    close(c)

    done <- true

}


func receiver(c chan int) {

    for result := range c {

        fmt.Println("received ", result)

    }

}


var list = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}


func main() {

    c := make(chan int)

    done := make(chan bool)

    go pop(&list, c, done)

    go receiver(c)

    go receiver(c)

    go receiver(c)

    <-done

    fmt.Println("done")

}

go run -race blah.go在弄乱 goroutine 时总是使用。


查看完整回答
反对 回复 2021-08-16
  • 1 回答
  • 0 关注
  • 185 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信