sync.Mutex
Use a mutex to protect shared mutable state when that is simpler than channel-based coordination.
Canonical guidance
- use a mutex when multiple goroutines coordinate around shared mutable state
- keep critical sections small and obvious
- treat lock ownership and protected invariants as part of the design
- prefer ordinary mutexes before reaching for more complex lock-free patterns
Use when
- maps or structs mutated by multiple goroutines
- caches
- shared counters with richer invariants than a single number
Avoid
- copying structs that contain a mutex after use begins
- exporting unlocked internal state casually
- replacing a straightforward mutex with channels just for style
Preferred pattern
type Cache struct {
mu sync.Mutex
m map[string]string
}
func (c *Cache) Set(k, v string) {
c.mu.Lock()
defer c.mu.Unlock()
c.m[k] = v
}
Anti-pattern
- protecting one invariant with several unrelated locks and unclear rules
Explanation: This anti-pattern is tempting in growing codebases, but unclear lock boundaries make deadlocks and invariant violations much harder to reason about.
Why
- mutexes are often the clearest concurrency primitive for shared state
Related pages
Sources
- sync package - Go Team
- The Go Memory Model - Go Team