Your requirements cannot be satisfied safely by any concrete design. As prescribed, you say that foo
and bar
can run in concurrent goroutines, and that if either or both of them have started, the other should wait for them both to finish. That is too weak of a prescription, though; what happens if foo
starts and then would finish, but bar
hasn't started running yet? What if bar
never runs at all? Or what if bar
runs, but foo
never does?
Are you mandating that both foo
and bar
must start and complete in order for your program to be correct? If so, I can guess as to what you meant to prescribe: You want a barrier that waits for them both to complete before proceeding.
package main
import (
"fmt"
"sync"
"time"
)
func foo() {
fmt.Println("foo")
}
func bar() {
fmt.Println("bar")
}
func within(wg *sync.WaitGroup, f func()) {
wg.Add(1)
go func() {
defer wg.Done()
f()
}()
}
func main() {
var wg sync.WaitGroup
within(&wg, foo)
within(&wg, bar)
wg.Wait()
fmt.Println("Both foo and bar completed.")
}
(That same example in the Playground)
Note that here, neither foo
nor bar
are mutually aware; only their callers are, in the interest of coordinating the two calls.
Your original attempt might lead you down the road of making foo
and bar
each close over or accept as a parameter a sync.WaitGroup
, with each function first adding itself to the group and waiting on it before exiting. That way lies madness.
If foo
starts and completes before bar
has a chance to add itself to the WaitGroup
, foo
will exit before bar
, even though you could claim they had been running concurrently, or the converse with bar
running before foo
can register its active state. Again, since this is a poorly specified aspect of your program, I suggest you instead focus on a higher-level barrier and not on the mutual dependence of these two functions.