All goroutines are asleep

瘦欲@ 提交于 2021-01-28 11:46:48

问题


I write some code which aims to synchronize using channel.

    var counter int64  // shared resource

    var wg sync.WaitGroup

    func main() {
        ch := make(chan int64)

        wg.Add(2)

        go incCounter(ch)
        go incCounter(ch)

        ch <- counter

        wg.Wait()
        fmt.Println("Final Counter:", counter) // expected value is 4
    }

    func incCounter(ch chan int64) {
        defer wg.Done()

        for count := 0; count < 2; count++ {
            value := <-ch
            value++
            counter = value
            ch <- counter
        }
    }

When I ran this program, an error happened: all goroutines are asleep - deadlock!. However I can't fix the problem and I don't know what is wrong. Could anyone help?


回答1:


Channels make(chan int) has implicit size zero ( ref: https://golang.org/ref/spec#Making_slices_maps_and_channels)

A channel of size zero is unbuffered. A channel of specified size make(chan int, n) is buffered. See http://golang.org/ref/spec#Send_statements for a discussion on buffered vs. unbuffered channels. The example at http://play.golang.org/p/VZAiN1V8-P illustrates the difference.

Here, channel <-ch or ch <- will be blocked until someone processes it (concurrently). If you try the flow of this program in pen and paper, you will figure it out why it is blocked. Below figure shows possible data flow through channel ch:

So if you make your ch := make(chan int64) to ch := make(chan int64,1), it will work.

var counter int64 // shared resource
var wg sync.WaitGroup

func main() {
    ch := make(chan int64, 1)

    wg.Add(2)

    go incCounter(ch)
    go incCounter(ch)

    ch <- counter

    wg.Wait()
    fmt.Println("Final Counter:", counter) // expected value is 4
}

func incCounter(ch chan int64) {
    defer wg.Done()

    for count := 0; count < 2; count++ {
        value := <-ch
        value++
        counter = value
        ch <- counter
    }
}

If we analyse how program works when you are using ch := make(chan int64), we can see that one go routine is blocked in this program(another one is exited). With the help of time.Sleep(n) and receiving the last data from the channel in the blocked go routine, we can overcome the deadlock. See the code below:

var counter int64 // shared resource
var wg sync.WaitGroup

func main() {
    ch := make(chan int64)

    wg.Add(2)

    go incCounter(ch)
    go incCounter(ch)

    ch <- counter

    // to ensure one go routine 'incCounter' is completed and one go routine is blocked for unbuffered channel
    time.Sleep(3*time.Second)

    <-ch // to unblock the last go routine

    wg.Wait()
    fmt.Println("Final Counter:", counter) // expected value is 4
}

func incCounter(ch chan int64) {
    defer wg.Done()

    for count := 0; count < 2; count++ {
        value := <-ch
        value++
        counter = value
        ch <- counter
    }
}


来源:https://stackoverflow.com/questions/53169598/all-goroutines-are-asleep

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!