Home > other >  All goroutines are asleep when reading from buffered channel
All goroutines are asleep when reading from buffered channel

Time:08-16


func writeToChan(wg *sync.WaitGroup, ch chan int, stop int) {
    defer wg.Done()
    for i := 0; i < stop; i   {
        ch <- i
    }
}

func readToChan(wg *sync.WaitGroup, ch chan int) {
    defer wg.Done()
    for n := range ch {
        fmt.Println(n)
    }
}

func main() {
    ch := make(chan int, 3)
    wg := new(sync.WaitGroup)    


    wg.Add(2)
    go writeToChan(wg, ch, 5)
    go readToChan(wg, ch)

    wg.Wait()
}
0
1
2
3
4
fatal error: all goroutines are asleep - deadlock!

I assume that the readToChan always reads continuously, and the writeToChan write to the channel and waits while the channel is read. I don't know why the output showed deadlock while I added two 'wait' to the WaitGroup.

CodePudding user response:

You need to close channel at the sender side. By using

for n := range ch {
    fmt.Println(n)
}

The loop will only stop when ch is closed

correct example:

package main

import (
    "fmt"
    "sync"
)

func writeToChan(wg *sync.WaitGroup, ch chan int, stop int) {
    defer wg.Done()
    for i := 0; i < stop; i   {
        ch <- i
    }
    close(ch)
}

func readToChan(wg *sync.WaitGroup, ch chan int) {
    defer wg.Done()
    for n := range ch {
        fmt.Println(n)
    }
}

func main() {
    ch := make(chan int, 3)
    wg := new(sync.WaitGroup)    


    wg.Add(2)
    go writeToChan(wg, ch, 5)
    go readToChan(wg, ch)

    wg.Wait()
}

CodePudding user response:

If close is not called on buffered channel, reader doesn't know when to stop reading. Check this example with for and select calls(to handle multi channels).

https://go.dev/play/p/Lx5g9o4RsqW

package mainimport (
"fmt"
"sync"
"time")func writeToChan(wg *sync.WaitGroup, ch chan int, stop int, quit chan<- bool) {
defer func() {
    wg.Done()
    close(ch)
    fmt.Println("write wg done")

}()
for i := 0; i < stop; i   {
    ch <- i
    fmt.Println("write:", i)
}
fmt.Println("write done")
fmt.Println("sleeping for 5 sec")
time.Sleep(5 * time.Second)
quit <- true
close(quit)}func readToChan(wg *sync.WaitGroup, ch chan int, quit chan bool) {
defer func() {
    wg.Done()
    fmt.Println("read wg done")
}()
//for n := range ch {
//  fmt.Println(n)
//}
//using Select if you have multiple channels.
for {
    //fmt.Println("waiting for multiple channels")
    select {
    case n := <-ch:
        fmt.Println("read:", n)
        // if ok == false {
        //  fmt.Println("read done")
        //  //return
        // }
    case val := <-quit:
        fmt.Println("recieved quit :", val)
        return
        // default:
        //  fmt.Println("default")
    }
}}func main() {
ch := make(chan int, 5)
ch2 := make(chan bool)
wg := new(sync.WaitGroup)
wg.Add(2)
go writeToChan(wg, ch, 3, ch2)
go readToChan(wg, ch, ch2)
wg.Wait()}
  •  Tags:  
  • go
  • Related