Reputation: 87
Can someone explain why this code throws an "fatal error: all goroutines are asleep - deadlock!"?
I can't seem to find what is wrong. I've seen some questions about this specific error, but the reason was mostly looping through a channel without closing it. Thank you!
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go wait(v, ch, wg)
fmt.Println(<-ch)
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration, wg sync.WaitGroup) {
defer wg.Done()
time.Sleep(seconds * time.Second)
c <- seconds
}
Upvotes: 0
Views: 1023
Reputation: 273416
You have to pass the WaitGroup
by reference, not by value. Otherwise the Done
has no effect. The documentation of this type says:
A WaitGroup must not be copied after first use.
Fix your code to this and it will work:
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go wait(v, ch, &wg)
fmt.Println(<-ch)
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration, wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(seconds * time.Second)
c <- seconds
}
It is also common to express this pattern as follows:
func main() {
ch := make(chan time.Duration)
var wg sync.WaitGroup
for _, v := range []time.Duration{5, 1} {
wg.Add(1)
go func() {
defer wg.Done()
wait(v, ch)
}()
fmt.Println(<-ch)
}
wg.Wait()
}
func wait(seconds time.Duration, c chan time.Duration) {
time.Sleep(seconds * time.Second)
c <- seconds
}
What's nice about this case is that wait
doesn't have to be aware of any wait groups (it could be a 3rd-party function, for example), and there's no confusion about passing a wait group by value or reference.
Upvotes: 4