Reputation: 2185
I'm setting up a chain of three goroutines, each with an input an output channel. The goroutines will read from the input channel until it's closed, increment the value, send it to the output channel. However, the program below deadlocks with this output:
goroutine 'one': 1
goroutine 'two': 2
goroutine 'three': 3
goroutine 'one': 10
goroutine 'two': 11
goroutine 'one': 100
fatal error: all goroutines are asleep - deadlock!
Code:
package main
import (
"fmt"
)
func int_channel(id string, i chan int, o chan int) {
defer close(o)
for x := range i {
fmt.Printf("goroutine '%s': %d\n", id, x)
o <- x + 1
}
fmt.Println("done")
}
func main() {
c0 := make(chan int)
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
go int_channel("one", c0, c1)
go int_channel("two", c1, c2)
go int_channel("three", c2, c3)
c0 <- 1
c0 <- 10
c0 <- 100
c0 <- 1000
c0 <- 10000
c0 <- 100000
close(c0)
fmt.Println("Sent all numbers to c0")
for x := range c3 {
fmt.Printf("out: %d\n", x)
}
}
Upvotes: 5
Views: 3940
Reputation: 22749
It hangs because the loop which reads from the output channel is never reached, thus the channels are not "emptyed" and once each channe has a value written into it no progress can be made and program hangs. To fix it write to the input in another goroutine, ie
func main() {
c0 := make(chan int)
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
go int_channel("one", c0, c1)
go int_channel("two", c1, c2)
go int_channel("three", c2, c3)
go func(){
c0 <- 1
c0 <- 10
c0 <- 100
c0 <- 1000
c0 <- 10000
c0 <- 100000
fmt.Println("Sent all numbers to c0")
close(c0)
}()
for x := range c3 {
fmt.Printf("out: %d\n", x)
}
}
IOW, when the line c0 <- 1
is executed, the value flows throught all three cannels and ends up in c3
, but since the reader loop is not reached yet, it just "sits in there". Then the line c0 <- 10
is executed, and this value ends up in c2
because it can't be written into c3
- the previous value is still in there, blocking the write. And thus when the line c0 <- 100
is executed, all channels are full and no further progress can be made.
Upvotes: 6
Reputation: 9116
You are not reading from c3
in a timely manner. You are sending way too many values into c0
. So the communication between channels happens like this:
send 1 on c0 => recv 1 on c1 => send 2 on c2 =>
recv 2 on c2 => send 3 on c3 => recv 3 on c3
send 10 on c0 => recv 10 on c1 => send 11 on c2 =>
recv 11 on c2 => send 12 on c3 -- // c3 still hasn't been read
// from and so send
// operation blocks here.
c0, c1 and c2 continue to receive until all their sends block eventually. You can refer to @ain's answer below for a solution.
Upvotes: 2