Что такое состояние гонки и к чему оно приводит
Что проверяют
Знаете ли вы, что в Go гонка это не просто иногда неверное число, а неопределённое поведение рантайма, и умеете ли выбирать между разделяемой памятью под мьютексом и передачей данных через канал.
Как отвечать
Состояние гонки возникает, когда две и более горутины обращаются к одной ячейке памяти, хотя бы одна пишет, и между обращениями нет упорядочивания. Последствия не сводятся к потерянному инкременту: многословные значения вроде интерфейса, среза или строки состоят из нескольких машинных слов и могут порваться на части, а одновременная запись в map роняет процесс фатальной ошибкой, которую recover не перехватывает.
Инструменты по порядку:
var mu sync.Mutex
mu.Lock()
counter++
mu.Unlock()
// либо без блокировок
atomic.AddInt64(&counter, 1)Дальше sync.RWMutex для преимущественно читающей нагрузки, sync.Once для однократной инициализации, каналы и errgroup там, где данные логичнее передать, чем защищать. Канал сам по себе является синхронизацией: отправка происходит раньше получения, и это даёт нужный порядок.
Обязательно назовите детектор: сборка и тесты с флагом -race подставляют инструментацию и печатают оба стека конкурирующих обращений.
Где спотыкаются
Считают детектор гарантией. Он динамический и видит только те пары обращений, которые реально случились в прогоне, поэтому редкая ветка проходит мимо. Отсутствие отчёта это не доказательство корректности.
Копируют структуру с мьютексом внутри: передали по значению, и у каждой копии оказался свой замок. Поэтому методы объявляют на указателе, а встроенный статический анализатор ругается на такое копирование не зря.
Защищают доступ, но не инвариант. Берут мьютекс на чтение, отпускают, принимают решение по прочитанному и снова берут на запись. Каждая операция атомарна, а проверка вместе с действием уже нет, и состояние успевает измениться в промежутке.