Вопрос

Я понимаю основную функцию ключевого слова lock из MSDN

оператор блокировки (ссылка на C #)

Ключевое слово lock помечает оператор block как критическую секцию, получая блокировку взаимного исключения для данного объекта, выполняя инструкцию, а затем снимая блокировку.

Когда следует использовать блокировку?

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

Есть ли проблемы с производительностью при использовании lock?

Я только что унаследовал приложение, которое использует блокировку везде, и оно однопоточное, и я хочу знать, должен ли я оставить их, нужны ли они вообще?

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

Это было полезно?

Решение

Когда следует использовать блокировку?

Блокировка должна использоваться для защиты общих ресурсов в многопоточном коде.Ни для чего другого.

Но нужно ли это, когда приложение не выделяет никаких других потоков?

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

Есть ли проблемы с производительностью при использовании lock?

ДА.Они не очень велики в однопоточном приложении, но зачем совершать вызовы, которые вам не нужны?

... является ли это хорошим шаблоном проектирования, которому следует следовать в будущем [?]

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

Другие советы

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

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

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

Поэтому, даже если ваше приложение является однопоточным, это может представлять опасность для вас.Учтите, что один метод в заблокированном блоке генерирует исключение, которое в конечном итоге не обрабатывается внутри блока.Даже если исключение обрабатывается по мере его появления в стеке вызовов, ваша критическая область кода не завершилась нормально.И кто знает, как отреагирует CLR?

Для получения дополнительной информации читайте эта статья об опасностях, связанных с потоками.Прервать ().

Имейте в виду, что могут быть причины, по которым ваше приложение не такое однопоточное, как вы думаете.Асинхронный ввод-вывод в .NET вполне может вызывать обратный вызов в потоке пула, например, как это делают некоторые из различных классов timer (однако, не таймер Windows Forms).

Вообще говоря, если ваше приложение является однопоточным, вы не получите большой пользы от оператора lock.Не зная точно вашего приложения, я не знаю, полезны они или нет, но я подозреваю, что нет.Кроме того, если ваше приложение использует блокировку везде, я не уверен, что я был бы так уверен в том, что оно работает в многопоточной среде в любом случае - сделал ли оригинальный разработчик на самом деле знаете, как разрабатывать многопоточный код, или они просто добавляли операторы блокировки повсюду в смутной надежде, что это сработает?

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

Блокировка на самом деле является сериализатором доступа к памяти, потоки (которые принимают блокировку) будут ожидать ввода блокировки до тех пор, пока текущий поток не выйдет из блокировки, поэтому доступ к памяти сериализуется.

Чтобы ответить на ваш вопрос, блокировка не нужна в однопоточном приложении, и у нее есть побочные эффекты в производительности.потому что блокировки в C # основаны на объектах синхронизации ядра, и каждая применяемая вами блокировка создает переход в режим ядра из пользовательского режима.

Если вас интересует производительность многопоточности, то хорошим местом для начала является Рекомендации по обработке потоков MSDN

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

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

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

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

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

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

Посмотрите на вопрос о "Мьютексе" в C #.А потом посмотрите на эти два вопросы, касающиеся использования инструкции 'lock(Object)' в частности.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top