In Golang, you can use a special closing channel to safely close multiple channels concurrently. Here's an example:
package main
import (
"fmt"
"sync"
)
func main() {
// Create a signal channel to close other channels
signalChan := make(chan bool)
// Create multiple worker channels
workerChans := make([]chan int, 5)
for i := 0; i < len(workerChans); i++ {
workerChans[i] = make(chan int)
}
// Start worker goroutines
for i := 0; i < len(workerChans); i++ {
go worker(workerChans[i], signalChan)
}
// Close all worker channels concurrently
go closeChannels(workerChans, signalChan)
// Wait for worker goroutines to finish
wg := sync.WaitGroup{}
wg.Add(len(workerChans))
for i := 0; i < len(workerChans); i++ {
go func(ch chan int) {
defer wg.Done()
for value := range ch {
fmt.Println(value)
}
}(workerChans[i])
}
// Wait for all goroutines to finish
wg.Wait()
}
// Worker function that processes values from the channel until it's closed
func worker(ch chan int, signalChan <-chan bool) {
for {
select {
case value, ok := <-ch:
if !ok {
return // Channel closed, worker goroutine is done
}
// Process value from channel
fmt.Println("Processing:", value)
case <-signalChan:
return // Close signal received, worker goroutine is done
}
}
}
// Function to close multiple channels with a single signal channel
func closeChannels(chans []chan int, signalChan chan<- bool) {
for _, ch := range chans {
close(ch)
}
close(signalChan)
}
In the above example, we create a signal channel (signalChan
) which will be used to instruct all worker goroutines to stop processing values. We also create multiple worker channels (workerChans
), each representing a separate worker goroutine.
To close all the worker channels concurrently, we launch a separate goroutine (closeChannels
) that loops through all the channels and closes each one. Finally, we close the signal channel to notify all the worker goroutines that they should stop processing.
We use a sync.WaitGroup
to wait for all the worker goroutines to finish processing and print their results.
Note that in the worker
function, we use a select statement to listen on both the worker channel and the signal channel. If a value is received on the worker channel, it is processed. If a value is received on the signal channel, the worker goroutine returns and terminates.
This approach ensures graceful shutdown of all worker goroutines and avoids potential data race conditions.