これは、結構オーソドックスな手法で、いろいろなところに使われています。
/*
お題: personが終了したらsubPerson1も subPerson2も強制的に終了させるには?
*/
package main
import (
"fmt"
"sync"
"time"
)
func subPerson1(i int, wg *sync.WaitGroup, ch chan struct{}) {
defer wg.Done()
<-ch // close(ch)が発行されるまでロック (普通はselect待ちにする)
fmt.Println(" End of sub_person1(", i, ")")
}
func subPerson2(i int, wg *sync.WaitGroup, ch chan struct{}) {
defer wg.Done()
<-ch // close(ch)が発行されるまでロック (普通はselect待ちにする)
fmt.Println(" End of sub_person2(", i, ")")
}
func person(i int, wg *sync.WaitGroup) {
fmt.Println(" Start... person(", i, ")")
defer wg.Done()
subWG := sync.WaitGroup{}
subWG.Add(2)
ch := make(chan struct{})
go subPerson1(i, &subWG, ch)
go subPerson2(i, &subWG, ch)
time.Sleep(10 * time.Second)
close(ch)
subWG.Wait()
fmt.Println(" End... person(", i, ")")
}
func main() {
fmt.Println("start... main()")
wg := sync.WaitGroup{}
for i := 0; i < 5; i++ {
wg.Add(1) // goルーチンを実行する関数分だけAddする
go person(i, &wg)
}
wg.Wait()
fmt.Println("end of ... main()")
}
出力結果はこんな感じです。
ちょっと変な感じがしますが、多分Printlnを記載している時間タイミングに因るものだろう、と思います。
$ go run main.go
start... main()
Start... person( 4 )
Start... person( 2 )
Start... person( 3 )
Start... person( 0 )
Start... person( 1 )
End of sub_person2( 2 )
End of sub_person2( 0 )
End of sub_person1( 0 )
End... person( 0 )
End of sub_person2( 4 )
End of sub_person1( 4 )
End... person( 4 )
End of sub_person2( 3 )
End of sub_person1( 3 )
End... person( 3 )
End of sub_person1( 2 )
End... person( 2 )
End of sub_person2( 1 )
End of sub_person1( 1 )
End... person( 1 )
end of ... main()