Взаимоблокировки потоков в NET Framework

В статье рассказывается про взаимоблокировки потоков в NET Framework. Описываются причины их возникновения и методы решения данной проблемы.

Что такое взаимоблокировки потоков

Взаимоблокировки потоков

Взаимоблокировка случается, когда каждый из двух потоков ожидает ресурс, удерживаемый другим потоком, поэтому ни один из них не может продолжить работу. Простейший способ проиллюстрировать это, предусматривает применение двух блокировок:

Три и более потока могут породить более сложные цепочки взаимоблокировок.

Среда CLR NET Framework в стандартной среде размещения не похожа на SQL Server; она не определяет и не разрешает автоматически взаимоблокировки, принудительно удаляя нарушителей. Взаимоблокировка потоков приводит к тому, что участвующие потоки блокируются на неопределенный срок, если только не был указан тайм-аут блокировки. (Тем не менее, под управлением хоста CLR на SQL Server взаимоблокировки обнаруживаются автоматически с генерацией на одном из потоков перехватываемого исключения.)

Взаимоблокировка представляет собой одну из самых сложных проблем многопоточности — особенно, когда имеется множество взаимосвязанных объектов. В сущности, сложная проблема заключается в том, что вы не уверены, какие блокировки получил вызывающий поток.

Таким образом, вы можете блокировать закрытое поле, а внутри своего класса х, не зная, что вызывающий поток (или поток, обращающийся к этому вызывающему потоку) уже заблокировал поле r в классе у. Тем временем, другой поток делает обратное, создавая взаимоблокировку. Как ни странно, проблема усугубляется (хорошими) шаблонами объектно-ориентированного проектирования, поскольку такие шаблоны создают цепочки вызовов, не определяемые вплоть до этапа выполнения.

Как избежать взаимоблокировки потоков

Популярный совет в данном вопросе — блокировать объекты в согласованном порядке во избежание взаимоблокировок — хотя и был полезен в начальном примере, труден в применении к только что описанному сценарию. Лучшая стратегия заключается в том, чтобы проявлять осторожность при блокировании вызывающих методов в объектах, которые могут иметь ссылки на ваш объект. Кроме того, имеет смысл подумать, действительно ли нужна блокировка вызывающих методов в других классах. Выбирая средства синхронизации более высокого уровня, такие как продолжения/комбинаторы задач, параллелизм данных и неизменяемые типы, можно снизить потребность в блокировании.

Существует альтернативный путь понимания этой проблемы: когда вы обращаетесь к другому коду, удерживая блокировку, инкапсуляция этой блокировки незаметно исчезает. Это не ошибка в CLR или NET Framework, а фундаментальное ограничение блокирования в целом. Проблемы блокирования решаются в рамках разнообразных исследовательских проектов, включая проект Software Transactional Memory (Транзакционная память программного обеспечения).

Другой сценарий взаимоблокировки возникает при вызове Dispatcher.Invoke (в приложении WPF) или Control.Invoke (в приложении Windows Forms) во время владения блокировкой. Если так случится, что пользовательский интерфейс выполняет еще один метод, который ожидает ту же самую блокировку, здесь как раз и возникнет взаимоблокировка. Часто это можно исправить, просто вызывая Beginlnvoke, вместо Invoke (или положиться на асинхронные функции, которые делают это неявно, когда присутствует контекст синхронизации). В качестве альтернативы можно перед вызовом Invoke освободить свою блокировку, хотя это не сработает, если вызывающий поток забрал блокировку.

 

 

Взаимоблокировки потоков в NET Framework
5 (100%) 3 votes

Поделиться в соц. сетях:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">