← Назад к вопросам
Приведи пример DeadLock
2.0 Middle🔥 161 комментариев
#Многопоточность и синхронизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример DeadLock
Что такое DeadLock?
DeadLock — ситуация, когда два или более потока бесконечно ждут друг друга и ни один не может продвинуться. Приложение зависает.
Классический пример: два мьютекса
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;
mutex mtx1, mtx2;
void thread1_func() {
cout << "Thread 1: захватываю mtx1\\n";
lock_guard<mutex> lock1(mtx1);
this_thread::sleep_for(chrono::milliseconds(100));
cout << "Thread 1: жду mtx2\\n";
lock_guard<mutex> lock2(mtx2); // DEADLOCK!
}
void thread2_func() {
cout << "Thread 2: захватываю mtx2\\n";
lock_guard<mutex> lock2(mtx2);
this_thread::sleep_for(chrono::milliseconds(100));
cout << "Thread 2: жду mtx1\\n";
lock_guard<mutex> lock1(mtx1); // DEADLOCK!
}
int main() {
thread t1(thread1_func);
thread t2(thread2_func);
t1.join();
t2.join();
}
Что происходит:
- Thread 1 захватывает mtx1
- Thread 2 захватывает mtx2
- Thread 1 ждёт mtx2 (захвачен T2)
- Thread 2 ждёт mtx1 (захвачен T1)
- DEADLOCK! Оба потока зависают
Пример с переводом денег
class Account {
public:
int balance;
mutex m;
Account(int b) : balance(b) {}
void transfer(Account& to, int amount) {
lock_guard<mutex> lock1(this->m); // Блокирую себя
this_thread::sleep_for(chrono::milliseconds(10));
lock_guard<mutex> lock2(to.m); // DEADLOCK!
this->balance -= amount;
to.balance += amount;
}
};
int main() {
Account acc1(1000), acc2(500);
// Thread 1: переводит из acc1 в acc2
thread t1(&Account::transfer, &acc1, ref(acc2), 100);
// Thread 2: переводит из acc2 в acc1
thread t2(&Account::transfer, &acc2, ref(acc1), 50);
t1.join(); // Зависает!
t2.join();
}
Порядок блокировок противоположный:
- t1: блокирует acc1 → ждёт acc2
- t2: блокирует acc2 → ждёт acc1
- DEADLOCK!
Как предотвратить?
1. Всегда блокировать в одном порядке
void transfer(Account& to, int amount) {
// Блокируем в порядке адресов
Account* first = (this < &to) ? this : &to;
Account* second = (this < &to) ? &to : this;
lock_guard<mutex> lock1(first->m);
lock_guard<mutex> lock2(second->m);
this->balance -= amount;
to.balance += amount;
}
2. std::lock для атомарной блокировки
void transfer(Account& to, int amount) {
lock(this->m, to.m); // Блокирует ОДНОВРЕМЕННО
lock_guard<mutex> l1(this->m, adopt_lock);
lock_guard<mutex> l2(to.m, adopt_lock);
this->balance -= amount;
to.balance += amount;
}
3. std::unique_lock с lock()
void transfer(Account& to, int amount) {
unique_lock<mutex> l1(this->m);
unique_lock<mutex> l2(to.m, defer_lock);
lock(l1, l2); // Атомарная блокировка
this->balance -= amount;
to.balance += amount;
}
Условия для DeadLock (Все 4 необходимы)
- Mutual Exclusion — ресурс для одного потока
- Hold and Wait — поток держит ресурс и ждёт другого
- No Preemption — нельзя отобрать ресурс
- Circular Wait — циклическая цепь ожидания
Признаки DeadLock
- Приложение зависает
- CPU не растёт
- Потоки в состоянии "wait"
- Нет ошибок, молча зависает