Your code has the following race condition
func nextStanza() <-chan map[string]string {
myChannel := make(chan map[string]string)
scanner := bufio.NewScanner(openStatusFile())
current := make(map[string]string)
go func() {
for scanner.Scan() {
mainline := scanner.Text()
line := strings.TrimSpace(mainline)
if strings.HasSuffix(line, "{") {
if len(current) != 0 {
myChannel <- current
}
result := strings.SplitN(line, " ", 2)
mu.Lock()
current["type"] = result[0]
mu.Unlock()
} else if strings.Contains(line, "=") {
result := strings.SplitN(line, "=", 2)
key := result[0]
val := result[1]
mu.Lock()
current[key] = val
mu.Unlock()
}
}
close(myChannel)
}()
return myChannel
}
When you start a goroutine on the anonymous function you are not creating a WaitGroup for it. What this means is that the function nextStanza()
is going to initiate the goroutine then return
without waiting for the anonymous goroutine to terminate - thus ending the goroutine upon the parent function's closure.
I would suggest using a waitgroup, this way you can guarantee that the anonymous function terminates.
A simple example illustrating what is occurring:
With a race condition
import (
"fmt"
"time"
// "sync"
)
func main() {
go func() {
time.Sleep(3 * time.Second)
fmt.Println("hai")
}()
return
}
Without a race condition
import (
"fmt"
"time"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
time.Sleep(3 * time.Second)
fmt.Println("hai")
wg.Done()
}()
wg.Wait()
return
}