简体   繁体   中英

All goroutines are asleep when reading from buffered channel


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.

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()
}

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 main 
    import (
    "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")
    }()
    //using rang over
    //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("received 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()
}

Output:

write: 0
write: 1
write: 2
write done
sleeping for 5 sec
read: 0
read: 1
read: 2
write wg done
received quit : true
read wg done

Program exited.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM