Problem Statement
Master all synchronization primitives in Go's sync package for building thread-safe applications.
sync.Mutex vs sync.RWMutex
// Mutex: exclusive access
type SafeCounter struct {
mu sync.Mutex
count int
}
func (c *SafeCounter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
// RWMutex: multiple readers OR one writer
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func (c *Cache) Get(key string) string {
c.mu.RLock()
defer c.mu.RUnlock()
return c.data[key]
}
func (c *Cache) Set(key, value string) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}sync.Once
var (
instance *Database
once sync.Once
)
func GetDB() *Database {
once.Do(func() {
instance = &Database{}
instance.Connect()
})
return instance
}
// Q: What if once.Do(f) panics?
// A: It counts as "done" - won't retry!sync.WaitGroup
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
process(i)
}(i)
}
wg.Wait() // Blocks until all Done() calledsync.Cond
// Broadcast to multiple waiting goroutines
type Barrier struct {
cond *sync.Cond
ready bool
}
func NewBarrier() *Barrier {
return &Barrier{
cond: sync.NewCond(&sync.Mutex{}),
}
}
func (b *Barrier) Wait() {
b.cond.L.Lock()
for !b.ready {
b.cond.Wait() // Releases lock while waiting
}
b.cond.L.Unlock()
}
func (b *Barrier) Release() {
b.cond.L.Lock()
b.ready = true
b.cond.Broadcast() // Wake all waiters
b.cond.L.Unlock()
}sync/atomic
import "sync/atomic"
var counter int64
// Atomic increment (faster than mutex for simple ops)
atomic.AddInt64(&counter, 1)
// Load/Store
val := atomic.LoadInt64(&counter)
atomic.StoreInt64(&counter, 100)
// Compare and Swap
swapped := atomic.CompareAndSwapInt64(&counter, 100, 200)
// atomic.Value for complex types
var config atomic.Value
config.Store(Config{Debug: true})
cfg := config.Load().(Config)sync.Map
// Use when: write-once read-many, or disjoint key sets
var m sync.Map
m.Store("key", "value")
val, ok := m.Load("key")
m.Delete("key")
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true // continue iteration
})Key Interview Questions
- Q: When sync.Map over regular map+mutex?
A: Write-once read-many, or disjoint key sets per goroutine. - Q: Cost of atomic vs mutex?
A: Atomics are hardware instructions (~5-10ns), mutex involves OS calls (~30-50ns). - Q: Is it safe to copy a sync.Mutex?
A: NO! It copies lock state, causing deadlocks.