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.

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

报告相同问题?

悬赏问题

  • ¥15 关于#stm32#的问题:CANOpen的PDO同步传输问题
  • ¥20 yolov5自定义Prune报错,如何解决?
  • ¥15 电磁场的matlab仿真
  • ¥15 mars2d在vue3中的引入问题
  • ¥50 h5唤醒支付宝并跳转至向小荷包转账界面
  • ¥15 算法题:数的划分,用记忆化DFS做WA求调
  • ¥15 chatglm-6b应用到django项目中,模型加载失败
  • ¥15 CreateBitmapFromWicBitmap内存释放问题。
  • ¥30 win c++ socket
  • ¥15 C# datagridview 栏位进度