Мертвая блокировка
Рисунок 7.1. Мертвая блокировка
Все остальные нити, пытающиеся получить доступ к стриммеру или кассете, также будут становиться в соответствующие очереди и ждать, пока администратор не снимет одну из "защелкнувшихся" задач.
Цикл взаимного ожидания может состоять и из большего количества нитей Возможна также мертвая блокировка с участием только одной нити и одного ресурса: для этого достаточно попытаться захватить одну и ту же флаговую переменную два раза. Критерием блокировки является образование замкнутого цикла в графе ожидающих друг друга задач.
Эта проблема может быть решена несколькими способами. Часто применяемое решение, обладающее, впрочем, серьезными недостатками — это отправка сообщения программе о том, что попытка установить примитив взаимоисключения приведет к мертвой блокировке. Это решение опасно во-первых, тем, что сильно усложняет кодирование: теперь мы вынуждены принимать во внимание не только возможность захвата примитива другой нитью, но и более сложные ситуации. Во-вторых, получив ошибку установки флага, программист испытывает сильный соблазн сделать именно то, чего делать в данном случае нельзя: повторить попытку захвата ресурса.
Рассмотрим ситуацию, когда две нити пытаются захватить необходимые им ресурсы, получают сообщение о возможности мертвой блокировки, и тут же повторяют попытку захвата того же ресурса. Поскольку освобождения ресурсов не происходит, взаимозависимость между этими нитями не устраняется, и повторный захват также приводит к сообщению о возможности мертвой блокировки. Если нити будут циклически повторять попытки захвата, мы получим состояние, которое называется живой блокировкой (livelock) (Рисунок 7.2). Это состояние реже рассматривается в учебниках, но теоретически оно ничуть не лучше мертвой блокировки. Практически же оно гораздо хуже — если нити, зацепившиеся намертво, тихо висят и причиняют вред только тем нитям, которым могли бы понадобиться занятые ими ресурсы, то нити, зацепившиеся заживо, непродуктивно расходуют время центрального процессора.