Почему блокировки только записи недостаточно? (check-then-act под замком) Контекст: конкуррентность и синхронизация потоков Если под замком находится только запись, сама проверка остаётся уязвимой к изменениям из других потоков В промежутке между проверкой и действием (act) может возникнуть состояние гонки (race condition) Частичная блокировка способна привести к чтению устаревших либо неконсистентных данных Для защиты нужен общий атомарный блок check+act → это предотвращает TOCTOU (time-of-check-to-time-of-use) Применяются расширенные примитивы синхронизации (mutex, rw-lock) или транзакции Практический результат: корректность и…
Почему блокировка только записи не защищает check-then-act?
Почему блокировки только записи недостаточно? (check-then-act под замком) Контекст: конкуррентность и синхронизация потоков Если под замком находится только запись, сама проверка остаётся уязвимой к изменениям из…
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Почему блокировки только записи недостаточно? (check-then-act под замком)
- Контекст: конкуррентность и синхронизация потоков
- Если под замком находится только запись, сама проверка остаётся уязвимой к изменениям из других потоков
- В промежутке между проверкой и действием (act) может возникнуть состояние гонки (race condition)
- Частичная блокировка способна привести к чтению устаревших либо неконсистентных данных
- Для защиты нужен общий атомарный блок check+act → это предотвращает TOCTOU (time-of-check-to-time-of-use)
- Применяются расширенные примитивы синхронизации (mutex, rw-lock) или транзакции
- Практический результат: корректность и консистентность данных, а также предотвращение логических ошибок и багов
Итог: одной блокировки записи недостаточно, чтобы защитить критическую секцию целиком; проверка и действие должны выполняться атомарно.
Развёрнутый ответ
Основной ответ
В паттерне check-then-act (проверить — затем выполнить действие) нельзя ограничиваться блокировкой только записи. Между завершением проверки и началом действия может возникнуть состояние гонки (race condition). Если замок не удерживается на всём этом участке, другой поток или процесс успеет изменить данные после проверки, но до действия. В результате поведение становится недетерминированным, а данные могут быть повреждены.
Ключевые моменты
- Проверку и действие необходимо выполнять атомарно: замок, установленный лишь на этапе действия, не предотвращает изменения данных после проверки.
- Если между check и act нет блокировки, возникает риск race condition. Например, два процесса могут одновременно увидеть одно и то же состояние и попытаться выполнить одинаковое действие, что вызовет конфликт.
- Более общее решение — заблокировать весь блок "check-then-act" либо применить атомарные операции или транзакции, например транзакцию в БД с Serializable Isolation Level.
Практический контекст
В многопоточных системах такая проблема часто появляется при обновлении счётчиков, проверке доступности ресурса и работе с пользовательскими кешами. В React 18 и Java Concurrent API для её устранения используют полные блокировки или атомарные классы, например AtomicBoolean. В распределённых системах с Redis применяют Lua-скрипты: вся операция check-then-act выполняется атомарно внутри Redis, а не защищается замком лишь частично.