I'm trying to use a for loop that continuously sends strings to different channels read by different goroutines. However, it gives me the error "all goroutines are asleep - deadlock!" Why is this happening? I searched for some answers, but I couldn't find an answer for this situation.
func main() {
var chans []chan string
for i := 0; i < 3; i++ {
chans = append(chans, make(chan string))
}
for i := 0; i < 3; i++ {
go sendString(chans[i])
}
for str := range chans[0] {
fmt.Print(str)
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
}
The errors are here. It prints "abcd", then generates the error, and if I delete the loop for printing, the program does not generate the error.
abcdfatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:18 +0x28d
goroutine 19 [chan send]:
main.sendString(0xc04203c120)
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
goroutine 20 [chan send]:
main.sendString(0xc04203c180)
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:24 +0x42
created by main.main
C:/Users/YuanZheng Hu/Desktop/Go Test/test/test.go:15 +0x175
exit status 2
I did the version using WaitGroup, but it seems not correct, and gives me the same error " all goroutines are asleep - deadlock!" where did I do wrong in the code below ?
func main() {
var myWaitGroup sync.WaitGroup
ch := make(chan string)
myWaitGroup.Add(1)
go sendString(ch, &myWaitGroup)
myWaitGroup.Wait()
close(ch)
time.Sleep(1 * time.Second)
}
func sendString(ch chan string, pg *sync.WaitGroup) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
defer pg.Done()
}
The second for loop will block until the channel is closed so you need to close it in the sending function. Also, you only read from the first channel so some of the data is lost. Doing this:
func main() {
var chans []chan string
for i := 0; i < 3; i++ {
chans = append(chans, make(chan string))
}
for i := 0; i < 3; i++ {
go sendString(chans[i])
}
for i := 0; i < 3; i++ {
for str := range chans[i] {
fmt.Print(str)
}
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
close(ch)
}
Will produce:
abcdabcdabcd
https://play.golang.org/p/7SoDKChnTbz
If you wanted to do this with a single channel as per your comment then you could add a wait group to close the channel once all the go routines are complete:
func main() {
c := make(chan string)
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
sendString(c)
wg.Done()
}()
}
go func() {
wg.Wait()
close(c)
}()
for str := range c {
fmt.Print(str)
}
}
func sendString(ch chan string) {
ch <- "a"
ch <- "b"
ch <- "c"
ch <- "d"
}