I have a function that, given a slice and an array, will send the elements of the slice to the channel one by one
package main
import (
"fmt"
)
var list1 = []string{"1", "2", "4"}
var list2 = []string{"11", "22", "44"}
func throw(ch chan string, list []string) {
for _, el := range list {
fmt.Println("Thrown ", el)
ch <- el
}
close(ch)
return
}
func main() {
c := make(chan string)
go throw(c, list1)
go throw(c, list2)
for i := range c {
fmt.Println("received ", i)
}
}
At some point the channel get closed, but one of the functions still needs to send data to it. How should I handle this? Making to separate channel seems the most reasonable choice here, but I want both data to pass through the same channel.
Go expects the code on the sending side of the channel to know whether the channel has been closed or not. So code like your snippet where each goroutine can close the channel without regard for the other is buggy.
One solution is to use a sync.WaitGroup
to coordinate when each goroutine has completed, and have a third goroutine perform the close. So you'd modify your throw
function to look something like:
func throw(ch chan string, list []string, wg *sync.WaitGroup) {
defer wg.Done()
// current body of function, without the close() call
}
And change the code that spawns the goroutines to the following:
var wg sync.WaitGroup
wg.Add(2)
go throw(c, list1, &wg)
go throw(c, list2, &wg)
go func() {
wg.Wait()
close(c)
}()
This way your channel will only be closed after the other two goroutines complete. You can experiment with this modified version of your example here: http://play.golang.org/p/nUiwjGglgU