Почему проблема с блокировкой (typeof (MyType))? - PullRequest
44 голосов
/ 21 октября 2009

MSDN выдает следующее предупреждение о ключевом слове lock в C #:

В общем, избегайте блокировки на общедоступных тип или экземпляры за пределами вашего кода контроль. Блокировка общих конструкций (это), блокировка (typeof (MyType)) и блокировка ("myLock") нарушать это руководство:

* lock (this) is a problem if the instance can be accessed publicly.
* lock (typeof (MyType)) is a problem if MyType is publicly accessible.

Тем не менее, это не дает никаких веских аргументов в пользу этого. Блокировка (это) объясняется здесь на SO . Я заинтересован в случае блокировки (typeof (MyType)). Что в этом опасного?

Спасибо.

Ответы [ 6 ]

59 голосов
/ 21 октября 2009

Это опасно, потому что блокировка может захватить что угодно, поэтому трудно или невозможно предотвратить тупиковую ситуацию.

Раньше была статья об этом («Не блокируйте объекты типа!», Статья доктора ГИП) с некоторыми комментариями Рико Мариани. По-видимому, статья больше не доступна напрямую, но вокруг нее плавают «зеркала», в том числе на http://bytes.com/topic/c-sharp/answers/249277-dont-lock-type-objects.

Вот выдержка:

Основная проблема здесь в том, что вы не являетесь владельцем объекта типа и не знаете, кто еще может получить к нему доступ. В общем, очень плохая идея полагаться на блокировку объекта, который вы не создали, и не знаете, кто еще может получить к нему доступ. Это вызывает тупик. Самый безопасный способ - блокировать только частные объекты.

Но подожди; это даже хуже, чем все это. Как выясняется, объекты типов иногда совместно используются доменами приложений (но не процессами) в текущих версиях среды выполнения .NET. (Обычно это нормально, поскольку они неизменны.) Это означает, что ДРУГОЕ ПРИЛОЖЕНИЕ, работающее даже в другом домене приложения (но в одном и том же процессе), может заблокировать ваше приложение, получив блокировку объекта типа, который вы хотите заблокировать. и никогда не выпускать его. И было бы легко получить доступ к этому объекту типа, потому что у объекта есть имя - полное имя типа! Помните, что блокировка lock / SyncLock (это вежливое слово для зависаний), пока не получит блокировку. Очевидно, действительно очень плохо полагаться на блокировку, которую может заблокировать другая программа или компонент, что приведет к тупику.

27 голосов
/ 21 октября 2009

Это та же проблема, что и с lock(this) - вы блокируете ссылку, к которой имеет доступ другой код, поэтому она может также блокировать ее.

Если у вас есть две несвязанные части кода, блокирующие одну и ту же ссылку без намерения исключить друг друга, то в лучшем случае вы можете потерять производительность из-за недостатка параллелизма в худшем случае вы можете ввести тупик.

2 голосов
/ 21 октября 2009

Поскольку результат typeof (MyType) (который является объектом типа Type) широко доступен, и другие потоки могут блокировать один и тот же объект и удерживать эту блокировку бесконечно. Тогда внутренняя логика MyType фактически дала значительный контроль над его логикой синхронизации. Это не может быть реальной проблемой, если это задумано, но код защиты / скептицизма должен быть вашим modus operandi .

0 голосов
/ 22 февраля 2018

Это не было бы "проблемой", если бы следовали этой модифицированной параллельной форме совета:

В общем, избегайте блокировки открытого типа или экземпляров , которые вы не создали или не определили . Общие конструкции lock (this), lock (typeof (MyType)) нарушают это правило , если вы не создали экземпляр или не объявили тип ..

Однако, поскольку вышеприведенное «не может быть гарантировано» для общедоступных типов или доступных экземпляров всего встречающегося кода, MSDN и другие источники утверждают, что их следует избегать при защитном программировании против единственного числа потенциальная трудно обнаруживаемая проблема во время выполнения (тупик) . Это хороший совет, учитывая, что большинство программистов не очень хорошо разбираются в правилах.

.. и тот, кто сталкивался с такой ошибкой в ​​дикой природе, был бы гораздо более непреклонен в том, что не разрешает повторение этой конкретной проблемы, навязывая изложенные рекомендации. (Java 1.0 / 1.1 с моделью интерфейса пользователя с резьбой AWT была особенно проблематичной.)

Случай lock ("mylock") является особенным в том смысле, что его следует избегать из-за интернирования строк, поскольку обычно невозможно «узнать», нарушают ли они приведенный выше совет.

0 голосов
/ 08 марта 2017

В нем также указана документация по теме «Лучшие практики управления потоками». https://msdn.microsoft.com/en-us/library/1c9txz50(v=vs.110).aspx

Это говорит;

Не используйте типы в качестве объектов блокировки. То есть избегайте такого кода, как блокировка (typeof (X)) в C # или SyncLock (GetType (X)) в Visual Basic или использование Monitor.Enter с объектами Type. Для данного типа есть только один экземпляр System.Type на домен приложения. Если тип Вы берете блокировку на общедоступный, код, отличный от вашего, может блокировать на нем, что приводит к тупикам . Для дополнительных проблем, см. Надежность Лучшие практики .

Соблюдайте осторожность при блокировке экземпляров, например lock (this) в C # или SyncLock (Me) в Visual Basic. Если другой код в вашем приложении, внешний по отношению к типу, блокирует объект, взаимоблокировки могут 1020 * происходят *.

0 голосов
/ 21 октября 2009

потому что целью блокировки является ТОЛЬКО установление места для хранения логического значения блокировки (заблокирован я или нет), чтобы другие потоки могли его увидеть ....

Распространенное заблуждение о том, что цель блокировки на самом деле каким-то образом блокируется, является просто неправильным ... То, что "заблокировано", это ... ничего, если только в методах, которые могут получить доступ к некоторой общей памяти небезопасным способом, вы пишете код, чтобы посмотреть на блокировку this, и не продолжаете работу до тех пор, пока она не будет снята ... используя объект Type, поскольку цель блокировки неверна, поскольку фрагменты кода в любом месте всего пространства процесса решения могут получить доступ к этому объекту типа и изменить блок синхронизации, в котором хранится логическая блокировка блокировки. Создание объекта с локальной областью позволяет вам лучше убедиться, что только те потоки и методы, которые могут получить доступ к вашей общей памяти «под угрозой» или связываться с ней, могут также получить доступ и / или изменить блокировку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...