M Receivers 1 Sender Closed By 3Party
It needed that the close signal must be made by a third-party goroutine. For such cases, we can use an extra signal channel to notify the sender to close the data channel.
- 多個接收端, 一個發送端, 但是由第三方gorotine來關閉. (ps : 01_M_Receivers_1_Sender, 由發送端關閉)
- 需要一個額外的channel 去通知 發送端去關閉
datachannel - 第三方 goroutine call
stop()functionstop := func(){ select{ case closing <-struct{}{}: <-closed case <-closed: } } - Sender 收到
closing信號 -> return -> run defer functionclose(closed);close(dataCh);
Exercises
https://go.dev/play/p/yHG4tvWACeY
package main
import (
"log"
"math/rand"
"sync"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
log.SetFlags(0)
// ...
const Max = 100000
const NumReceivers = 100
const NumThirdParties = 15
wgReceivers := sync.WaitGroup{}
wgReceivers.Add(NumReceivers)
// ...
dataCh := make(chan int)
closing := make(chan struct{}) // signal channel
closed := make(chan struct{})
// The stop function can be called
// multiple times safely.
stop := func() {
select {
case closing <- struct{}{}:
<-closed
case <-closed:
}
}
// some third-party goroutines
for i := 0; i < NumThirdParties; i++ {
go func() {
r := 1 + rand.Intn(3)
time.Sleep(time.Duration(r) * time.Second)
stop()
}()
}
// The Sender
go func() {
defer func() {
close(closed)
close(dataCh)
}()
for {
select {
case <-closing:
return
default:
}
select {
case <-closing:
return
case dataCh <- rand.Intn(Max):
}
}
}()
// Receivers
for i := 0; i < NumReceivers; i++ {
go func() {
defer wgReceivers.Done()
for value := range dataCh {
log.Println(value)
}
}()
}
wgReceivers.Wait()
}