Explain Go's memory model and what happens-before guarantees mean in practice
go-sen-001
Your answer
Answer as you would in a real interview — explain your thinking, not just the conclusion.
Model answer
Go's memory model defines when a write to a variable is guaranteed to be visible to a concurrent read. The rule is happens-before: if operation A synchronises-before B, A's writes are visible to B. Goroutine creation, channel send/receive pairs, sync.Mutex lock/unlock, sync.Once.Do, and sync/atomic operations all establish happens-before edges. If two goroutines access shared memory without any synchronisation between them, the behaviour is a data race — undefined, and flagged by the race detector. In practice: protect shared mutable state with a Mutex, use channels to transfer ownership of data, or use sync/atomic for simple counters. Never rely on 'it works today' — the compiler and CPU both reorder memory operations within a goroutine, making apparent correctness without synchronisation fragile.
Code example
type SafeCounter struct {
mu sync.Mutex
v map[string]int
}
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
defer c.mu.Unlock()
c.v[key]++
}
func (c *SafeCounter) Value(key string) int {
c.mu.Lock()
defer c.mu.Unlock()
return c.v[key]
}
// Run tests with: go test -race ./...
Follow-up
What is the difference between a data race and a race condition? Can you have a race condition without a data race?