Что такое deadlock в многопоточности
Что проверяют
Понимаете ли вы механику взаимной блокировки и умеете ли назвать условия, при которых она возникает. Ответ по определению из учебника слабый, ждут причин и способов профилактики.
Как отвечать
Взаимная блокировка это ситуация, когда два и более потока навсегда ждут друг друга: каждый держит ресурс, нужный соседу, и ждёт ресурс, который держит сосед. Программа не падает, а просто перестаёт двигаться, и в этом главная неприятность.
Классические условия, при одновременном выполнении которых блокировка возможна:
- ресурс удерживается монопольно;
- поток держит один ресурс и ждёт другой;
- отобрать ресурс принудительно нельзя;
- есть кольцо ожидания.
Достаточно разорвать любое условие. На практике самое дешёвое это единый порядок захвата: если все потоки берут блокировки в одном и том же порядке, кольца не возникает. Дальше идут таймауты вместо бесконечного ожидания (tryLock с временем), уменьшение области под блокировкой, отказ от вложенных блокировок и замена разделяемого состояния на передачу сообщений.
В Go у вопроса своя специфика: чаще блокируются не на мьютексах, а на каналах. Запись в канал, который никто не читает, чтение из канала, куда никто не пишет, забытый wg.Done(), close не тем, кто владеет каналом. Если встали все горутины сразу, рантайм это замечает и печатает fatal error: all goroutines are asleep - deadlock!, но при живой фоновой горутине программа просто зависает без сообщения.
Диагностика: дамп горутин по SIGQUIT или через pprof, в Java jstack с автоматическим поиском циклов, в базах отдельный лог блокировок.
Где спотыкаются
Путают взаимную блокировку с гонкой данных: гонка это неверный результат, блокировка это остановка.
Не отличают livelock, когда потоки активно работают, но не продвигаются.
Считают, что -race найдёт дедлок. Он ищет гонки, а не взаимные блокировки.