Взаимоблокировка — это ситуация, когда два или более потока не могут продолжить выполнение, потому что каждый ждет ресурса, захваченного другим потоком из этой же группы.
Основные условия для возникновения взаимоблокировки (условия Кофмана):
- Взаимное исключение (Mutual Exclusion): Ресурс может быть использован только одним потоком одновременно.
- Удержание и ожидание (Hold and Wait): Поток, удерживающий один (или более) ресурс, ожидает получения других ресурсов, которые заняты другими потоками.
- Неперехватываемость (No Preemption): Невозможно принудительно отобрать ресурс у потока, который его удерживает. Ресурс может быть освобожден только потоком-владельцем.
- Циклическое ожидание (Circular Wait): Существует замкнутая цепочка потоков, где каждый поток в цепочке ждет ресурс, удерживаемый следующим потоком в этой же цепочке.
Пример простого сценария с двумя потоками и двумя мьютексами:
cpp
Способы предотвращения или обнаружения взаимоблокировок:
- Предпочтительный способ - избегание:
- Всегда захватывать мьютексы в фиксированном, глобально определенном порядке.
- Использовать средства, управляющие захватом нескольких мьютексов атомарно (например,
std::lock с несколькими аргументами).
- Избегать захвата мьютексов на долгое время.
- Попытка захвата мьютекса с таймаутом (
try_lock_for).
- Обнаружение и восстановление:
- Разработка механизмов для обнаружения циклического ожидания и последующего принудительного освобождения ресурсов (часто сложно реализовать правильно в многопоточных системах общего назначения).
- Использование специальных инструментов анализа (статический анализ, динамический анализ).