Golang / GoLang Concurrency Mastery Interview Questions
What is the check-then-act race condition (TOCTOU) and how do you fix it?
The Time Of Check, Time Of Use (TOCTOU) race: a goroutine checks a condition, releases the lock, then acts — but between check and act another goroutine changes the condition. The fix is to hold the lock for the entire check-and-act sequence, or use an atomic compare-and-swap.
// BUGGY: check-then-act race â lock released between check and act type Cache struct { mu sync.Mutex items map[string]string } func (c *Cache) GetOrComputeBuggy(key string, compute func() string) string { c.mu.Lock() val, ok := c.items[key] // CHECK c.mu.Unlock() if ok { return val } // â Another goroutine may compute and cache here result := compute() // expensive â no lock held c.mu.Lock() c.items[key] = result // ACT â may overwrite another goroutine's result c.mu.Unlock() return result } // FIX 1: singleflight â one computation per key at a time import "golang.org/x/sync/singleflight" var group singleflight.Group func (c *Cache) GetOrComputeSF(key string, compute func() string) string { v, _, _ := group.Do(key, func() (any, error) { c.mu.Lock() if val, ok := c.items[key]; ok { c.mu.Unlock() return val, nil } c.mu.Unlock() result := compute() c.mu.Lock() c.items[key] = result c.mu.Unlock() return result, nil }) return v.(string) } // FIX 2: sync.Map.LoadOrStore â atomic check-and-store var sm sync.Map actual, loaded := sm.LoadOrStore(key, expensiveValue) // CAUTION: expensiveValue is computed before the call regardless
More Related questions...