This is by no mean the definitive guide. I’m just going to highlight some tools and patterns in concurrency programming that I have seen.

Mutex

Extremely useful when guarding a variable unsafe read and writes.

  • RWMutex
  • Mutex
  • var mu sync.Mutex struct not pointer

func (s *myStruct) GetItem() *Item {
    s.mu.RLock()
    defer s.mu.RUnlock()
    return s.item
}

Waitgroup for synchronization/orchestration

var wg &sync.Waitgroup
wg.Add(num)
for i := 0; i < num; i ++ {
    // start consumer
    go func() {
        setUpCode()
        wg.Done()
    }()
}
// Wait for everything to be ready
wg.Wait()

Channels for two way sync

commC := make(chan struct{})
go func() {
    // blocks until setup 1 is done
    commC<-struct{}{}
    // set up 2
    close(commC)
    doMoreStuffTogether()
}()
// setup 1
<-commC
<-commC
doStuffTogether()

Singleflight


g := &singleflight.Group{}
// this will ensure multiple concurrent calls to this won't do the connection stuff multiple times.
x, y := g.Do(func() (int, int){
    // do some connection stuff
    return 1, 2
    })

Atomic int and bool

  • Add, subtract, compare and swap
  • Use 1 and 0 for bool
func f() {
    var x int 
    atomic.StoreInt(&x, 1)
}