2つのgoroutineの片方が終了したら、他方も終了させる方法

お題: subPerson1が終了したら subPerson2も巻き添えで強制的に終了させるには?
当初、一方が終了したら、他方も終了するように作りたかったのだけど、いいやり方が思いつかなかったので、subPerson1 → subPerson2 の順番で終わせるような実装にした。
まあ、subPerson1を送信専用、subPerson2を受信専用のgoroutineとすれば、まあ、いけるんじゃないかな、と
/*
	お題: subPerson1が終了したら subPerson2も巻き添えで強制的に終了させるには?
	当初、一方が終了したら、他方も終了するように作りたかったのだけど、分からなかったので、subPerson1 → subPerson2 の順番で終わせるような実装にした
*/

package main

import (
	"fmt"
	"sync"
	"time"
)

func subPerson1(i int, wg *sync.WaitGroup, ch chan struct{}) {
	defer wg.Done()
	time.Sleep(1 * time.Second)
	fmt.Println("		End of sub_person1(", i, ")")
	close(ch) // subPerson2に終了を通知する
}

func subPerson2(i int, wg *sync.WaitGroup, ch chan struct{}) {
	defer wg.Done()
	<-ch // subPerson1 の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)

	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()")
}
出力結果
ebata@DESKTOP-P6KREM0 MINGW64 ~/goga/0-2
$ go run main.go
start... main()
        Start... person( 4 )
        Start... person( 0 )
        Start... person( 1 )
        Start... person( 3 )
        Start... person( 2 )
                End of sub_person1( 3 )
                End of sub_person2( 3 )
        End... person( 3 )
                End of sub_person1( 0 )
                End of sub_person1( 4 )
                End of sub_person2( 4 )
        End... person( 4 )
                End of sub_person2( 0 )
        End... person( 0 )
                End of sub_person1( 1 )
                End of sub_person2( 1 )
        End... person( 1 )
                End of sub_person1( 2 )
                End of sub_person2( 2 )
        End... person( 2 )
end of ... main()

とまあこんな感じで、sub_person1 → sub_person2 → person という順番でgoroutineが終了していることが確認できました。

2021/12,江端さんの技術メモ

Posted by ebata