Как называется код, который нужно оборачивать в Mutex?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Критическая секция (Critical Section) — что это?
Код, который нужно оборачивать в Mutex, называется критической секцией (Critical Section). Это фундаментальное понятие в многопоточном программировании.
Определение
Критическая секция — это участок кода, в котором один поток получает доступ к общему ресурсу (переменная, файл, база данных). Если несколько потоков будут выполнять этот код одновременно, возникнет race condition (состояние гонки).
Пример проблемы (без Mutex)
import threading
counter = 0
def increment():
global counter
# Это — критическая секция!
for _ in range(1000000):
counter += 1
def decrement():
global counter
# Это — критическая секция!
for _ in range(1000000):
counter -= 1
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=decrement)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Результат: {counter}") # Может быть 0, -100, 50 или другое значение!
Проблема: операция counter += 1 в Python это три действия:
- Прочитать значение из памяти
- Добавить 1
- Записать обратно
Поток может быть прерван между шагами, и другой поток прочитает старое значение. Результат непредсказуем.
Решение: оборачивание Mutex
import threading
counter = 0
mutex = threading.Lock()
def increment():
global counter
for _ in range(1000000):
with mutex: # Критическая секция
counter += 1
def decrement():
global counter
for _ in range(1000000):
with mutex: # Критическая секция
counter -= 1
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=decrement)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Результат: {counter}") # Всегда 0!
Как это работает:
- Только один поток может находиться внутри
with mutex:одновременно - Другие потоки ждут, пока первый завершит работу
- Гарантируется консистентность данных
Типы критических секций
1. Read-Modify-Write (RMW)
Это самый распространённый тип:
# Критическая секция: прочитать-изменить-написать
with mutex:
value = shared_data['balance'] # Read
value -= 100 # Modify
shared_data['balance'] = value # Write
2. Проверка условия перед действием
with mutex:
if len(queue) > 0: # Check
item = queue.pop() # Action
Без Mutex другой поток может удалить элемент между Check и Action.
3. Обновление структур данных
with mutex:
# Вставка в словарь и добавление в список должны быть атомарны
cache[key] = value
access_log.append((key, time.time()))
Различные механизмы синхронизации в Python
Lock (Mutex)
import threading
lock = threading.Lock()
with lock:
# Критическая секция
pass
RLock (переиспользуемый Mutex)
Если один поток должен несколько раз заблокировать один и тот же Mutex:
import threading
rlock = threading.RLock()
def outer():
with rlock:
inner()
def inner():
with rlock: # Одна thread может заблокировать RLock несколько раз
pass
Semaphore
Огранничить доступ нескольким потокам одновременно:
import threading
sem = threading.Semaphore(3) # Максимум 3 потока одновременно
with sem:
# Критическая секция
pass
Event и Condition Variable
import threading
condition = threading.Condition()
# Поток 1: ждёт условие
with condition:
condition.wait() # Освобождает lock и ждёт
# Критическая секция
# Поток 2: сигнализирует
with condition:
# Критическая секция
condition.notify() # Пробуждает ждущие потоки
Правила для критических секций
1. Минимизируйте размер критической секции
# Плохо: все операции внутри Mutex
with mutex:
result = expensive_calculation() # Это может занять время!
shared_data = result
# Хорошо: только необходимое внутри
result = expensive_calculation()
with mutex:
shared_data = result
2. Избегайте вложенных критических секций (deadlock)
# Плохо: может привести к deadlock
with lock1:
with lock2:
critical_section()
# Лучше: всегда берите в одном порядке
with lock1, lock2:
critical_section()
3. Не вызывайте блокирующие операции внутри критической секции
# Плохо: I/O внутри Mutex
with mutex:
response = requests.get('http://api.example.com') # Может зависнуть!
process(response)
# Хорошо: I/O вне Mutex
response = requests.get('http://api.example.com')
with mutex:
process(response)
Пример: потокобезопасный кэш
import threading
from typing import Any, Optional
class ThreadSafeCache:
def __init__(self):
self._cache = {}
self._lock = threading.Lock()
def get(self, key: str) -> Optional[Any]:
with self._lock: # Критическая секция: чтение
return self._cache.get(key)
def set(self, key: str, value: Any) -> None:
with self._lock: # Критическая секция: запись
self._cache[key] = value
def delete(self, key: str) -> None:
with self._lock: # Критическая секция: удаление
self._cache.pop(key, None)
def clear(self) -> None:
with self._lock: # Критическая секция: очистка
self._cache.clear()
Заключение
- Критическая секция — это код, работающий с общими ресурсами
- Mutex (Lock) защищает критическую секцию от одновременного доступа
- Правило: если несколько потоков могут одновременно читать/писать переменную → это критическая секция
- Во время разработки спросите: какие переменные разделяют мои потоки? Их должны защищать Mutex!