Приведи пример дедлока
Что проверяют
Знаете ли вы, как тупик выглядит именно в Go: не только на мьютексах, но и на каналах. И понимаете ли границы встроенного детектора: в живом сервисе рантайм про тупик обычно молчит, и искать его приходится по стекам горутин.
Как отвечать
Начните с самого короткого примера:
func main() {
ch := make(chan int) // без буфера
ch <- 1 // принимать некому
}Программа падает с сообщением о том, что все горутины спят. Дальше механизм: небуферизованный канал требует встречи отправителя и получателя, а отправитель тут единственная горутина. Сюда же относятся чтение из канала, который никто не закроет, range по нему, любая операция с nil-каналом и wg.Wait() при потерянном wg.Done().
Второй пример на мьютексах: разный порядок захвата в двух горутинах даёт классическую инверсию. Скажите, что sync.Mutex не рекурсивный: метод под блокировкой, вызывающий другой метод того же объекта с той же блокировкой, встанет навсегда. У sync.RWMutex вложенный RLock тоже опасен, потому что ожидающий писатель не пропускает новых читателей.
Закончите диагностикой: рантайм ругается, только когда спят все горутины разом, а в сервисе всегда живут таймеры и сетевой опрос. Поэтому смотрят дамп стеков через SIGQUIT или GOTRACEBACK=all, профиль goroutine, а в коде опираются на context с дедлайном и defer mu.Unlock().
Где спотыкаются
Первое: считают детектор гарантией. Пример с двумя заблокированными горутинами и time.Sleep в main не падает вовсе: спящая горутина считается живой, программа завершается, а в продакшене та же ситуация выглядит как утечка горутин и растущая память.
Второе: думают, что go test -race ловит тупики. Детектор гонок про одновременный доступ к памяти, зависшую горутину он не покажет, тест просто провисит до таймаута. Зато go vet ловит соседнюю ошибку, копирование структуры с мьютексом по значению: блокировка защищает копию.
Третье: теряют разблокировку на ранних выходах. Ветка с return по ошибке без defer mu.Unlock(), wg.Done() внутри условия, отправка в канал из горутины, которую после отмены контекста никто не читает. Всё это не падает сразу и всплывает под нагрузкой.