Напишите псевдокод многопоточной программы, где происходит дедлок при использовании двух мьютексов m1 и m2; объясните причины дедлока и предложите стратегии предотвращения (упорядочивание, trylock, время ожидания, обнаружение и восстановление).

12 Ноя в 10:27
7 +7
0
Ответы
1
Псевдокод, вызывающий дедлок (два потока захватывают мьютексы в разном порядке):
Пусть мьютексы m1m_1m1 , m2m_2m2 ; потоки T1T_1T1 , T2T_2T2 .
T1:
lock(m1m_1m1 )
// делает часть работы
lock(m2m_2m2 )
// критическая секция
unlock(m2m_2m2 )
unlock(m1m_1m1 )
T2:
lock(m2m_2m2 )
// делает часть работы
lock(m1m_1m1 )
// критическая секция
unlock(m1m_1m1 )
unlock(m2m_2m2 )
Причина дедлока (Coffman conditions):
- Взаимное исключение (mutual exclusion): каждый мьютекс эксклюзивен.
- Удержание и ожидание (hold-and-wait): T1T_1T1 держит m1m_1m1 и ждёт m2m_2m2 ; T2T_2T2 держит m2m_2m2 и ждёт m1m_1m1 .
- Непрерываемость (no preemption): мьютексы не могут быть принудительно отобраны.
- Кольцевая блокировка (circular wait): T1→m2→T2→m1→T1T_1 \rightarrow m_2 \rightarrow T_2 \rightarrow m_1 \rightarrow T_1T1 m2 T2 m1 T1 .
Стратегии предотвращения и примеры (плюсы/минусы коротко):
1) Упорядочивание захвата (static ordering)
- Правило: каждый поток должен захватывать мьютексы в согласованном порядке, например m1m_1m1 перед m2m_2m2 .
Псевдокод:
Любой поток, нуждающийся в обоих:
lock(m1m_1m1 )
lock(m2m_2m2 )
...
unlock(m2m_2m2 )
unlock(m1m_1m1 )
- Плюсы: просто, эффективно; устраняет circular wait.
- Минусы: требует глобальной политики, не всегда применимо при динамическом наборе ресурсов.
2) trylock с откатом и экспоненциальным бэкоффом
Псевдокод (для двух мьютексов):
while true:
lock(m1m_1m1 )
if try_lock(m2m_2m2 ):
break
else:
unlock(m1m_1m1 )
sleep(backoff())
// повторить
// критическая секция
unlock(m2m_2m2 )
unlock(m1m_1m1 )
- Плюсы: избегает блокировки навсегда; прост в реализации.
- Минусы: возможны лишние повторные попытки и живучесть (livelock) без правильного бэкоффа.
3) Таймаут при блокировке (timed lock)
Псевдокод:
if timed_lock(m1m_1m1 , ttt):
if timed_lock(m2m_2m2 , ttt):
// критическая секция
unlock(m2m_2m2 )
unlock(m1m_1m1 )
else:
unlock(m1m_1m1 )
// обработка неудачи (повторить/ошибка)
else:
// обработка неудачи
- Плюсы: даёт гарантию возврата в случае ожидания; гибче.
- Минусы: нужно выбирать ttt и обрабатывать откаты; может усложнить логику.
4) Обнаружение и восстановление (deadlock detection & recovery)
- Идея: позволить ресурсы захватываться, периодически строить wait-for граф; при обнаружении цикла — выбрать жертву (roll back, принудительно прервать поток или отнять ресурсы) и освободить ресурсы.
Псевдокод мониторинга:
periodically:
build_wait_for_graph()
if cycle_detected(graph):
victim = select_victim(cycle) // критерии: минимальная стоимость отката
terminate_or_rollback(victim)
- Плюсы: применимо при динамичных ресурсах.
- Минусы: сложность детекции, стоимость восстановления, возможна потеря работы.
Короткие рекомендации:
- Если можно задать глобальный порядок — используйте его (самый простой и быстрый).
- Для динамики — trylock/timeout с бэкоффом.
- В системах с критичной надежностью — детекция и восстановление (или транзакции с откатом).
- Комбинируйте подходы: порядок для большинства случаев + таймаут/trylock для редких динамических ситуаций.
12 Ноя в 11:21
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир