Data race vs race condition
На ревью Миша и Аня спорили о биллинге: доступ везде под мьютексом, а баланс клиента уходил в минус. Аня развела два термина: баг конфигурации — data race, а счёт биллинга — логическая гонка, с которой мьютекс не справился.
data race — конкретный класс несинхронизированного доступа к памяти, race condition — широкий класс ошибок порядка операций; детектор ловит первое и не видит второе.
Data race
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
Два обращения к памяти без happens-before, одно из них запись. Это data race — формальная ошибка, ловится race detector'ом. Программа некорректна: исходы ограничены моделью памяти, но ничего хорошего не гарантировано — гонка всегда баг.
Race condition
mu.Lock()
enough := balance >= amount // проверка
mu.Unlock()
if enough {
mu.Lock()
balance -= amount // списание — уже в другой секции
mu.Unlock()
}
Всё под мьютексом — data race нет, детектор молчит. Но между «проверил баланс» и «списал» может вклиниться другая горутина и изменить баланс: решение принято по устаревшему состоянию, и баланс уходит в минус. Ошибка порядка операций при формально синхронизированном доступе — это race condition. Детектор её не видит: формально всё синхронизировано.
Разведём термины: race condition — широкий класс ошибок порядка операций; data race — конкретный класс несинхронизированного доступа к памяти. Классы не совпадают: поучительнее всего логическая гонка без data race — ровно то, что показывает этот пример.
Почему их путают
Обе — про конкурентность, обе проявляются «иногда». Разница — в уровне: data race — про то, как горутины обращаются к памяти (формально, машинно проверяемо), race condition — про то, что код делает с данными (семантически, проверяется только головой). Данные могут быть идеально защищены от гонок — и всё равно иметь логическую гонку между операциями.
Вы узнаете:
- почему
-raceне сертификат корректности - какие реальные примеры check-then-act в сервисах
Проверьте себя
Два атомика total и count обновляются парой, а читаются по отдельности. Что это?
Кто ловит логическую гонку (race condition)?
«Всё под одним мьютексом» — достаточное условие корректности?
правильных ответов
Data race — несинхронизированный доступ, ловится инструментами. Race condition — неверный порядок операций, ловится ревью и тестами: логическая гонка возможна и без data race. Мьютекс закрывает первое, но не второе.
10 000 ₽ · 60 минут · онлайн