atomically closing termination channels in Go

done := make(chan struct{})for {
select {
case <-done:
return
case job := <-jobs:
// execute job
}
}

Approaches to closing this done channel

c.mu.Lock()
if c.err != nil {
c.mu.Unlock()
return // already canceled
}
c.err = err
if c.done == nil {
c.done = closedchan
} else {
close(c.done)
}
var once sync.Onceonce.Do(func() {
close(done)
})
import (
"sync"
"testing"
)
func TestClose(t *testing.T) {
done := make(chan struct{})
closer := func() {
select {
case <-done:
default:
close(done)
}
}
wg := sync.WaitGroup{}
wg.Add(10000)
for i := 0; i < 10000; i++ {
go func() {
wg.Done()
closer()
}()
}
wg.Wait()
}

What about channels where you communicate data?

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store