duandong1963 2014-09-19 12:49
浏览 28
已采纳

即使关闭了通道,例程也陷入僵局

I have a list, with a function that pop element from it, and another function that "receives" the popped elements. I thought that putting a close after the receiver would close the channel, but it seems that the program is deadlock before getting there. Which is the best way of doing this? Should I have another channel that detects when the pop are done?

Playground link

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条回答 默认 最新

  • douqulv6059 2014-09-19 12:56
    关注

    There are so many problems with the code, let's see.

    1. your pop function doesn't lock when accessing the slice, so that's a data race right there.
    2. for len(list) > 0 {} is a data race because you're accessing list while modifying it in 2 other goroutines.
    3. for len(list) > 0 {} will never return because you have 3 items in your list but you call pop only twice.
    4. receiver(c) errors because of #3, it tries to read from the channel but there's nothing writing to it.

    One way to do it is to use one writer (pop) and multiple readers (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")
    }
    

    <kbd>playground</kbd>

    Always use go run -race blah.go when messing with goroutines.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥30 YOLO检测微调结果p为1
  • ¥20 求快手直播间榜单匿名采集ID用户名简单能学会的
  • ¥15 DS18B20内部ADC模数转换器
  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题