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

Data race и владелец-синхронизатор

После разбора команда договорилась: у каждой общей переменной должен быть хозяин, который синхронизирует доступ. Первым вопросом на ревью стало: кто владеет счётчиком. Ответ «никто» Аня закрывала как баг, даже если код работал.

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

data race — это два обращения к одной ячейке без happens-before, и хотя бы одно из них запись; у любой общей переменной должен быть синхронизирующий владелец.

Определение гонки

Go

Две операции обращаются к одной ячейке памяти, хотя бы одна из них запись, и между ними нет happens-before. Такая программа некорректна, но исходы ограничены моделью памяти: для однословной ячейки читатель видит реально записанное старое или новое значение — out-of-thin-air значения запрещены. Смесь значений из разных записей возможна только для многословных объектов — структур, интерфейсов, слайсов, карт, строк. В примере int — одно слово, поэтому читатель увидит либо старое, либо новое значение.

Владелец-синхронизатор

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

  • Данные ходят через канал: владелец — канал.
  • Доступ под мьютексом: владелец — мьютекс.
  • Значение обновляется атомарно: владелец — атомик.

Всё остальное — гонка, даже если на конкретной машине и конкретной версии Go «работает». Вопрос «кто владеет этой переменной» стоит задавать про каждую общую переменную при ревью.

«просто прочитать и так сойдёт» не работает

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

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

Вы узнаете:

  • почему гонка может не проявляться годами
  • как гонка ловится -race
Задание · вопросы

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

Вопрос 1 из 3

Код с гонкой стабильно работает неделю. Что это доказывает?

Вопрос 2 из 3

Одна горутина читает counter, другая делает counter++. Что скажет -race?

Вопрос 3 из 3

При гонке на однословной ячейке что видит читатель?

Итоги

Гонка = два обращения без happens-before, одно из них запись. Лекарство — синхронизирующий владелец у каждой общей переменной: канал, мьютекс или атомик.

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