Reputation: 7869
I'm not sure what I'm missing but I get a deadlock error. I'm using a buffered channel that I range over after all go routines complete. The channel has the capacity of 4 and I'm running 4 go routines so I'm expecting it to be "closed" automatically once it reaches the max capacity.
package main
import "fmt"
import "sync"
func main() {
ch := make(chan []int, 4)
var m []int
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
ch <- m
return
}()
}
wg.Wait()
for c := range ch {
fmt.Printf("c is %v", c)
}
}
Upvotes: 6
Views: 5673
Reputation: 1387
@Denys Séguret is right
but follow is anohter Solution easier to fix it:
func main() {
ch := make(chan []int, 4)
var m []int
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
ch <- m
return
}()
}
go func() {
wg.Wait()
close(ch)
}()
for c := range ch {
fmt.Printf("c is %v", c)
}
}
form https://go.dev/blog/pipelines Fan-out, fan-in 's func merge()
func merge(cs ...<-chan int) <-chan int {
var wg sync.WaitGroup
out := make(chan int)
// Start an output goroutine for each input channel in cs. output
// copies values from c to out until c is closed, then calls wg.Done.
output := func(c <-chan int) {
for n := range c {
out <- n
}
wg.Done()
}
wg.Add(len(cs))
for _, c := range cs {
go output(c)
}
// Start a goroutine to close out once all the output goroutines are
// done. This must start after the wg.Add call.
go func() {
wg.Wait()
close(out)
}()
return out
}
Upvotes: 1
Reputation: 1
you can try run this code that don`t have wg ,and still deadlock ; why? Just because the main goroutine is blocked by the ch , so the program is suspended and timeout , and you get an deadlock error. The essential reason is that ch is blocking the main goroutine.
func main() {
ch := make(chan []int, 4) // No matter which int number
var m []int
for i := 0; i < 5; i++ {
go func() {
ch <- m
return
}()
}
for c := range ch {
fmt.Printf("c is %v \n", c)
}
}
Upvotes: 0
Reputation: 382514
You have two problems :
range ch
is still waiting for elements to come in the channel and there's no goroutine left to write on it.Solution 1 :
Make the channel big enough and, close it so that range
stops waiting :
ch := make(chan []int, 5)
...
wg.Wait()
close(ch)
This works but this mostly defeats the purpose of channels here as you don't start printing before all tasks are done.
Solution 2 :
This solution, which would allow a real pipelining (that is a smaller channel buffer), would be to do the Done()
when printing :
func main() {
ch := make(chan []int, 4)
var m []int
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
ch <- m
return
}()
}
go func() {
for c := range ch {
fmt.Printf("c is %v\n", c)
wg.Done()
}
}()
wg.Wait()
}
Upvotes: 10
Reputation: 229342
I'm running 4 go routines
No, you're running 5 - thus the deadlock, as the channel buffers only 4 messages.
However, iterating over the channel will later on deadlock the program too. Since the channel isn't closed, it'll block forever once it read your 5 values.
So,
ch := make(chan []int, 5)
and
close(ch)
before the range
loop.
Upvotes: 9