zoukankan      html  css  js  c++  java
  • why is this a deadlock in golang / waitgroup?

    问题:

    I'm not sure what I'm missing but I get a deadlock error. I'm using a buffered channel that I range over after all go routines complete. The channel has the capacity of 4 and I'm running 4 go routines so I'm expecting it to be "closed" automatically once it reaches the max capacity.

    package main
    
    import "fmt"
    import "sync"
    
    func main() {
        ch := make(chan []int, 4)
        var m []int
    
        var wg sync.WaitGroup
        for i := 0; i < 5; i++ {
            wg.Add(1)
            go func() {
                defer wg.Done()
                ch <- m
                return
            }()
        }
        wg.Wait()
    
        for c := range ch {
            fmt.Printf("c is %v", c)
        }
    }


    You have two problems :

    • there's not enough place for all the goroutines as your channel is too small : when your channel is full, the remaining goroutines must wait for a slot to be freed
    • range ch is still waiting for elements to come in the channel and there's no goroutine left to write on it.

    Solution 1 :

    Make the channel big enough and, close it so that range stops waiting :

    ch := make(chan []int, 5)
    ...
    wg.Wait()
    close(ch)
    

    Demonstration

    This works but this mostly defeats the purpose of channels here as you don't start printing before all tasks are done.

    Solution 2 : This solution, which would allow a real pipelining (that is a smaller channel buffer), would be to do the Done() when printing :

    func main() {
        ch := make(chan []int, 4)
        var m []int
    
        var wg sync.WaitGroup
        for i := 0; i < 5; i++ {
            wg.Add(1)
            go func() {
                ch <- m
                return
            }()
        }
        go func() {
            for c := range ch {
                fmt.Printf("c is %v
    ", c)
                wg.Done()
            }
        }()
        wg.Wait()
    }
    

    Demonstration

    •  
      why range ch is still waiting for elements if the channel is drained ? I assumed that once I send the 4th value the range reaches the end of "loop" so it should no longer wait for values. – hey Jul 7 '14 at 12:02 
    •  
      range waits until the channel is closed. That's how it works. This way you can launch a goroutine and have it still work if you push elements into the channel later. – Denys Séguret Jul 7 '14 at 12:04 
    •  
      thanks for the answer , though it's curious because I have an app that does just the same thing except it doesn't go into deadlock. It loops through some sql rows , launches go routines, I wg.Wait() after the for loop, range over the channel and display the results of each routine. There is no "close(ch)" operation. I can only assume that the program itself goes into deadlock but I don't get the error. – hey Jul 7 '14 at 12:10
    •  
      Concerning the 2nd solution I'm not sure I understand but it still goes into deadlock except that the error is not thrown in main ? – hey Jul 7 '14 at 12:13
    •  
      sorry ... I think I've got how it works after all. Anyway shouldn't wg.Done() be after fmt.Printf("c is %v ", c) play.golang.org/p/Be8eEc6PMu – hey Jul 7 '14 at 12:41


  • 相关阅读:
    java线程池
    缓存命中
    dubbo面向服务使用
    ActiveMQ
    创建证书
    struts2的运行原理以及底层的工作机制
    jdbc,mybatis,hibernate各自优缺点及区别
    struts2与springmvc的区别
    linux vi 命令编辑操作
    Linux FTP基本操作命令 ( 序列二 ftp)
  • 原文地址:https://www.cnblogs.com/oxspirt/p/14685519.html
Copyright © 2011-2022 走看看