Deadlock after attempting to print values of channel using 'range'

Issue

Here is my code at Go Playground

package main

import (
    "fmt"
)

func sum_up(my_int int, cs chan int) {
    my_sum := 0
    for i := 0; i < my_int; i++ {
        my_sum += i
    }
    cs <- my_sum
}

func main() {

    my_channel := make(chan int)
    for i := 2; i < 5; i++ { 
        go sum_up(i, my_channel)
    }


    for ele := range my_channel {
        fmt.Println(ele)
    }  

    //fatal error: all goroutines are asleep - deadlock!

    fmt.Println("Done")

}

Which results in:

1
3
6
fatal error: all goroutines are asleep - deadlock!

And I don’t understand what causes the error. My understanding is that in my function sum_up I am adding new values to my_channel. Why does the problem occur after I try to print out the values? Since I see 1,3,6 are printed it means that all goroutines have successfully finished.

Moreover, if the block that attempts to print the values of the channel

    for ele := range my_channel {
        fmt.Println(ele)
    }

Is removed, then I don’t get the error. So it is including the block that causes the error, but why?

Solution

A for-range on a empty channel will block until there are elements to read from the channel or until the channel is closed.

Here is a version that uses sync.WaitGroup to account for how many goroutines remain active. After all goroutines have finished, the channel is closed and the for-range loop exists.

https://play.golang.org/p/ZnLYxLMNdF

package main

import (
    "fmt"
    "sync"
)

func sum_up(my_int int, cs chan int, wg *sync.WaitGroup) {
    my_sum := 0
    for i := 0; i < my_int; i++ {
        my_sum += i
    }
    cs <- my_sum
    wg.Done()
}

func main() {
    wg := &sync.WaitGroup{}
    my_channel := make(chan int)
    for i := 2; i < 5; i++ {
        wg.Add(1)
        go sum_up(i, my_channel, wg)
    }

    // Run a goroutine that will monitor how many sum_up are running.
    go func(cs chan int, wg *sync.WaitGroup) {
        wg.Wait()
        close(cs)
    }(my_channel, wg)

    for ele := range my_channel {
        fmt.Println(ele)
    }

    //fatal error: all goroutines are asleep - deadlock!

    fmt.Println("Done")

}

Answered By – siritinga

Answer Checked By – Terry (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.