Golang / GoLang Concurrency Mastery Interview Questions
What causes deadlocks in Go and how do you detect and prevent them?
A deadlock occurs when every goroutine is blocked waiting for a resource held by another — a circular dependency from which no goroutine can proceed. The Go runtime detects simple all-goroutine deadlocks and panics with 'all goroutines are asleep — deadlock!'.
// DEADLOCK 1: circular channel wait ch1 := make(chan int) ch2 := make(chan int) go func() { v := <-ch1; ch2 <- v }() // waits for ch1, then sends ch2 go func() { v := <-ch2; ch1 <- v }() // waits for ch2, then sends ch1 // ALL goroutines blocked â runtime: 'all goroutines are asleep' // DEADLOCK 2: non-reentrant mutex locked twice var mu sync.Mutex mu.Lock() mu.Lock() // DEADLOCK â tries to acquire a lock already held // DEADLOCK 3: inconsistent lock-acquisition order var muA, muB sync.Mutex // goroutine 1: muA.Lock() then muB.Lock() (AâB order) // goroutine 2: muB.Lock() then muA.Lock() (BâA order) â DEADLOCK // FIX for #3: enforce a global consistent ordering â always A before B // DEADLOCK 4: unbuffered send with no receiver // ch := make(chan int) // ch <- 1 // blocks forever // Detection tools: // 1. Go runtime: 'all goroutines are asleep' // 2. CTRL+\ sends SIGQUIT â dumps all goroutine stacks // 3. pprof goroutine endpoint: /debug/pprof/goroutine?debug=2 // 4. context.WithTimeout prevents indefinite blocking
Prevention rules: (1) acquire locks in a globally consistent order. (2) Prefer context.Context with deadlines over raw channel waits. (3) Use select with default or a timeout to avoid indefinite blocking. (4) Keep critical sections short and never hold a lock while performing I/O.
More Related questions...