В приложении ASP.NET у меня есть ресурс, защищенный ReaderWriterLockSlim.

Обычные запросы вызывают EnterReadLock, обращаются к ресурсу, вызывают ExitReadLock и возвращаются.

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

Достаточно справедливо: если в конце запроса A поток не выходит из блокировки, и этот же поток используется для обработки запроса B и пытается войти в блокировку, он будет сброшен.

Теперь мой вопрос: возможен ли следующий сценарий? причины?

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

Если да, какое другое решение у меня есть для защиты указанного ресурса? Имея в виду, что я хочу использовать ReaderWriterLockSlim, потому что у меня также есть другой поток, который может записывать в ресурс?

изменить: добавить некоторые детали:

1) Это происходит в методе ProcessRequest HttpHandler, который генерирует, кэширует и обслуживает изображения. Эти изображения дорого генерировать. Таким образом, первый запрос будет генерировать и кэшировать изображение, и мы хотим приостановить другие запросы во время генерации.

2) Мы не пытались "воспроизвести" - в данный момент мы пытаемся узнать, возможно ли, чтобы тот же поток начал обработку запроса, уже ожидая, пока изображение станет готов.

3) Мне известно о LockPolicyRecursion, но я не уверен, что полностью понимаю его назначение, и можно ли в нашем случае установить для него значение SupportsRecursion.

изменить: идем дальше...

Согласно документу, указанному Райаном ниже, поток блокируется и не возвращается в пул, пока мы не выполняем асинхронные операции. Поэтому, как только мы заблокировали поток, ожидающий завершения EnterReadLock, он не вернется в пул и не обработает какой-либо другой запрос.

Итак, 1) мы должны быть в безопасности, но 2) мы можем голодать в пуле потоков. Предполагая, что мы не хотим немедленно возвращать фиктивное изображение «пожалуйста, подождите», какие у нас есть решения?

3
Stephen 9 Фев 2010 в 16:05
1
- пока ссылка действительна, я думаю, это скроет настоящую проблему; этот код не преднамеренно использует рекурсивные блокировки.
 – 
Marc Gravell
9 Фев 2010 в 16:13
@Mauricio: не уверен, что я полностью понимаю точную цель LockRecursionPoliciy и не был ли он создан для использования в подобных случаях. @Марк: точно. Тем не менее, я не могу придумать другой способ сделать это?
 – 
Stephen
9 Фев 2010 в 16:37
Извините, неправильно понял вопрос.
 – 
Mauricio Scheffer
9 Фев 2010 в 16:50

2 ответа

Да, это возможно в ASP.NET. Есть некоторые места (асинхронные и т. д.), где ASP.NET выполняет переключение потоков и использует разные потоки для одного запроса (в разных точках), что означает, что вполне возможно, что на полпути через запрос этот поток переходит к обработке < em>другой запрос.

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

1
Marc Gravell 9 Фев 2010 в 16:10
Смотрите мои правки: возьмите и снимите блокировку в ProcessRequest HttpHandler. Один поток может некоторое время удерживать блокировку (в режиме записи) и некоторые операции ввода-вывода при удержании блокировки.
 – 
Stephen
9 Фев 2010 в 16:35

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

Пул потоков должен освобождать поток только в том случае, если он простаивает (т. е. находится в спящем режиме). Таким образом, вы ожидаете, что если ваш защищенный код не приводит к бездействию потока, то поток не должен освобождаться, пока он находится в блокировке — просто убедитесь, что вы выходите из блокировки (всегда выйти в блоке finally)

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

РЕДАКТИРОВАТЬ: если вы создаете изображения, вы должны получить блокировку записи, которая заблокирует все блокировки чтения. Ни блокирующие, ни заблокированные потоки не будут использоваться повторно, поэтому у вас не должно возникнуть проблем.

Источник

0
Ryan Emerle 9 Фев 2010 в 17:03
@Ryan: «блокирующие потоки не возвращаются в пул», можете ли вы указать мне на какую-нибудь страницу, документирующую это? Самому найти не удалось.
 – 
Stephen
9 Фев 2010 в 17:39
@Ryan: К сожалению, я пропустил вашу ссылку «Источник». В настоящее время читаю.
 – 
Stephen
9 Фев 2010 в 18:06