Home > Mobile >  Deadlocks with buffered channels in Go
Deadlocks with buffered channels in Go

Time:11-13

I am encountering for the below code fatal error: all goroutines are asleep - deadlock!

Am I right in using a buffered channel? I would appreciate it if you can give me pointers. I am unfortunately at the end of my wits.

func main() {
    valueChannel := make(chan int, 2)
    defer close(valueChannel)
    var wg sync.WaitGroup
    for i := 0; i < 10; i   {
        wg.Add(1)
        go doNothing(&wg, valueChannel)
    }

    for {
        v, ok := <- valueChannel
        if !ok {
            break
        }
        fmt.Println(v)
    }
    wg.Wait()
}

func doNothing(wg *sync.WaitGroup, numChan chan int) {
    defer wg.Done()
    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
    numChan <- 12
}

CodePudding user response:

The main goroutine blocks on <- valueChannel after receiving all values. Close the channel to unblock the main goroutine.

func main() {
    valueChannel := make(chan int, 2)
    var wg sync.WaitGroup
    for i := 0; i < 10; i   {
        wg.Add(1)
        go doNothing(&wg, valueChannel)
    }

    // Close channel after goroutines complete.
    go func() {
        wg.Wait()
        close(valueChannel)
    }()

    // Receive values until channel is closed. 
    // The for / range loop here does the same
    // thing as the for loop in the question.
    for v := range valueChannel {
        fmt.Println(v)
    }
 }

Run the example on the playground.

CodePudding user response:

The main problem is on the for loop of channel receiving. The comma ok idiom is slightly different on channels, ok indicates whether the received value was sent on the channel (true) or is a zero value returned because the channel is closed and empty (false). In this case the channel is waiting a data to be sent and since it's already finished sending the value ten times : Deadlock. So apart of the design of the code if I just need to do the less change possible here it is:

func main() {
    valueChannel := make(chan int, 2)
    defer close(valueChannel)
    var wg sync.WaitGroup
    for i := 0; i < 10; i   {
        wg.Add(1)
        go doNothing(&wg, valueChannel)
    }

    for i := 0; i < 10; i   {
        v := <- valueChannel

        fmt.Println(v)
    }
    wg.Wait()
}

func doNothing(wg *sync.WaitGroup, numChan chan int) {
    defer wg.Done()
    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
    numChan <- 12
}
  • Related