猿问

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

我有一个列表,其中包含一个从中弹出元素的函数,以及另一个“接收”弹出元素的函数。我认为在接收器之后关闭会关闭通道,但是在到达那里之前程序似乎已经死锁了。这样做的最佳方法是什么?我是否应该有另一个通道来检测流行音乐何时完成?

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")


}


MMTTMM
浏览 186回答 1
1回答

人到中年有点甜

代码有很多问题,让我们看看。您的pop函数在访问切片时不会锁定,因此这就是数据竞争。for len(list) > 0 {}&nbsp;是数据竞争,因为您正在访问列表,同时在其他 2 个 goroutine 中修改它。for len(list) > 0 {}&nbsp;永远不会返回,因为您的列表中有 3 个项目,但您只调用了两次 pop。receiver(c)&nbsp;由于 #3 导致的错误,它尝试从通道读取但没有写入任何内容。一种方法是使用一个写入器 (&nbsp;pop) 和多个读取器 (&nbsp;receiver):func pop(list *[]int, c chan int, done chan bool) {&nbsp; &nbsp; for len(*list) != 0 {&nbsp; &nbsp; &nbsp; &nbsp; result := (*list)[0]&nbsp; &nbsp; &nbsp; &nbsp; *list = (*list)[1:]&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("about to send ", result)&nbsp; &nbsp; &nbsp; &nbsp; c <- result&nbsp; &nbsp; }&nbsp; &nbsp; close(c)&nbsp; &nbsp; done <- true}func receiver(c chan int) {&nbsp; &nbsp; for result := range c {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("received ", result)&nbsp; &nbsp; }}var list = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}func main() {&nbsp; &nbsp; c := make(chan int)&nbsp; &nbsp; done := make(chan bool)&nbsp; &nbsp; go pop(&list, c, done)&nbsp; &nbsp; go receiver(c)&nbsp; &nbsp; go receiver(c)&nbsp; &nbsp; go receiver(c)&nbsp; &nbsp; <-done&nbsp; &nbsp; fmt.Println("done")}go run -race blah.go在弄乱 goroutine 时总是使用。
随时随地看视频慕课网APP

相关分类

Go
我要回答