Связаться с нами: info@exonya.com или (+7 812) 982-2514

  • Русский
  • English

EXONYA
Разработка программ, веб-дизайн, продвижение (SEO, SMM)

Взаимоблокировки на .NET Framework

Автор EXONYA в . Опубликовано новости компании, Mobile software development, Разработка программ

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

Простейший способ проиллюстрировать это предусматривает применение двух блокировок:

 

object lockerl = new object(); object locker2 = new object();

new Thread (() => {

lock (lockerl)

{

Thread.Sleep (1000);

lock (locker2); // Взаимоблокировка

}

}) . Start () ;

lock (locker2)

{

Thread.Sleep (1000);

lock (lockerl); // Взаимоблокировка

}

 

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

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

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

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

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

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

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

Теги: , , , , , , ,

EXONYA

Software Development Company, Custom Software Development, Offshore Programming, Software Outsourcing