Guard shared data. Don't share by communicating? You're allowed — use channels OR a mutex, whichever fits.
Mutex — one-at-a-time access
Zero value is an unlocked mutex. Never copy a Mutex after first use — put it in a pointer or on a struct kept by pointer.
type Counter struct {
mu sync.Mutex
n int
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.n++
}
RWMutex — many readers, one writer
Reach for RWMutex only when reads vastly outnumber writes. For contention-light cases a plain Mutex is faster.
var mu sync.RWMutex
// reader side
mu.RLock()
v := cache[k]
mu.RUnlock()
// writer side
mu.Lock()
cache[k] = v
mu.Unlock()