Deadlock — взаимная блокировка, когда горутины ждут друг друга. Основные правила для предотвращения:
1. Единый порядок блокировки — всегда захватывай мьютексы в одном порядке.
2. Таймауты — используй context.WithTimeout и select с time.After.
3. Избегай вложенных блокировок — не захватывай второй мьютекс, удерживая первый.
4. Каналы вместо мьютексов — CSP-стиль сложнее привести к deadlock.
// deadlock: обе горутины ждут друг друга
select {
case ch1 <- val:
case <-ctx.Done():
return ctx.Err() // таймаут спасает от вечной блокировки
}
Go рантайм детектит простейшие deadlock-и (все горутины заблокированы) и паникует с fatal error: all goroutines are asleep.