Not everything fits channels. sync.Mutex protects shared memory; sync.WaitGroup waits for goroutines to finish. Prefer channels for ownership transfer; use mutexes for shared caches and counters.
WaitGroup pattern
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
// work
}()
wg.Wait()
Mutex basics
mu.Lock() / mu.Unlock()—always defer Unlock in functions. sync.RWMutex allows concurrent reads when writes are rare.
Important interview questions and answers
- Q: Channels vs mutexes?
A: Channels for communication and ownership; mutexes for shared state—"share memory by communicating" is the Go proverb, but mutexes are idiomatic for caches. - Q: WaitGroup misuse?
A: Add/Done mismatch causes hang or panic—match counts carefully; call Add before starting goroutine.
Self-check
- What does WaitGroup.Wait block on?
- Why defer mu.Unlock()?
Pitfall: Copying a sync.Mutex by value breaks locking—pass pointers or keep mutexes in structs accessed by pointer.
Interview prep
- Channels vs mutex?
Channels for communication; mutexes for protecting shared mutable state like caches.
- WaitGroup pitfall?
Add/Done mismatch hangs or panics—call Add before starting goroutine.