Материал проходит вычитку — возможны неточности.
Урок 89 из 118

Дедлок и нереентерабельность

Ночью конвейер встал: файлы перестали обрабатываться, алерты молчали до утра. Разбор показал дедлок — один путь дважды брал блокировку и вешал сам себя. Миша разделил код, и утренний деплой вернул конвейер в строй.

Главная мысль

мьютексы дедлочатся двумя способами: циклическим порядком захвата и повторным захватом той же горутиной — Go-мьютекс нереентерабелен.

Циклический порядок

Go

Классический дедлок: две горутины захватывают одни и те же мьютексы в разном порядке. Каждая ждёт ту блокировку, которую держит другая. Лекарство — единый порядок захвата во всём коде: всегда mu1 раньше mu2, тогда цикл невозможен.

Нереентерабельность

func (s *Stats) Snapshot() int {
    s.mu.Lock()
    defer s.mu.Unlock()
    return s.Value() // Value сам делает Lock — deadlock
}

func (s *Stats) Value() int {
    s.mu.Lock()
    defer s.mu.Unlock()
    return s.processed
}

В отличие от блокировок в Java или C#, Go-мьютекс нереентерабелен: повторный Lock той же горутиной — дедлок, а не «счётчик вложенности». Вызвал метод, который сам берёт мьютекс, из секции того же мьютекса — повесился. Лечится разделением: публичный метод берёт мьютекс, внутренний — нет (valueLocked).

Почему нереентерабельность — это хорошо

Звучит как ограничение, но это осознанный выбор: реентерабельность поощряет «просто заверни всё в мьютекс» — а это прямая дорога к длинным секциям и скрытым гонкам по инвариантам. Нереентерабельность заставляет думать, где граница секции и кто владеет данными, — ровно то, чему посвящён следующий урок.

В следующем уроке

Вы узнаете:

  • как рантайм детектит дедлок
  • как RWMutex связан с дедлоком рекурсивного RLock
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

var mu sync.Mutex; mu.Lock(); mu.Lock() в одной горутине. Что произойдёт?

Вопрос 2 из 3

Как лечить циклический захват двух мьютексов в разном порядке?

Вопрос 3 из 3

Почему нереентерабельность — фича, а не баг?

Итоги

Дедлоки: разный порядок захвата и повторный Lock. Единый порядок захвата + разделение публичных и внутренних методов.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки