Ответ
Состояние гонки (race condition) — это ошибка проектирования многопоточной системы, при которой результат работы зависит от непредсказуемого порядка выполнения операций в разных потоках. Это происходит, когда несколько потоков одновременно обращаются к общему изменяемому ресурсу (переменной, файлу) без должной синхронизации.
Ключевая проблема: неатомарность операций
Даже простая операция, как counter += 1
, на самом деле состоит из нескольких шагов:
- Чтение текущего значения
counter
из памяти. - Увеличение этого значения в регистре процессора.
- Запись нового значения обратно в память.
Если два потока выполняют эти шаги вперемешку, одно из обновлений может быть потеряно.
Пример на Python
Этот код должен в итоге вывести 1_000_000
, но из-за состояния гонки результат будет непредсказуемо меньше.
import threading
counter = 0
def increment():
global counter
for _ in range(100000):
# Эта операция неатомарна и вызывает race condition
counter += 1
threads = [threading.Thread(target=increment) for _ in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"Финальное значение счетчика: {counter}")
# Пример вывода: Финальное значение счетчика: 345123
Решение: использование блокировок (Locks)
Для предотвращения состояния гонки используются примитивы синхронизации, например, мьютексы или блокировки (Lock
). Они гарантируют, что только один поток может выполнять критический участок кода в один момент времени.
import threading
counter = 0
lock = threading.Lock()
def safe_increment():
global counter
for _ in range(100000):
with lock: # Блокировка приобретается при входе в блок
# Этот код выполняет только один поток одновременно
counter += 1
# Блокировка автоматически освобождается при выходе
threads = [threading.Thread(target=safe_increment) for _ in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"Финальное значение счетчика: {counter}")
# Вывод всегда будет: Финальное значение счетчика: 1000000