Страницы

Поиск по вопросам

среда, 3 октября 2018 г.

Допустимо ли использовать yield return внутри блокировки?

Есть два вопроса к коду, приведенному ниже:
Допустимо ли использовать yield return внутри блокировки? Что произойдёт с блокировкой, когда мы будет крутить метод Get() в цикле foreach?
public IEnumerable Get() { _lock.EnterReadLock(); try { foreach (var item in _dictionary) { yield return new SomeObject(item.Key, item.Value); } } finally { _lock.ExitReadLock(); } }
private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();


Ответ

Смотрите, это возможно на уровне языка — компилятор не имеет возможности проверить. Но делать так не рекомендуется.
Общее правило такое: следует избегать вызова чужого кода под блокировкой. Допустим, вы нарушили правило и выполнили yield под блокировкой. Клиентский код может при этом сделать вызов в другой поток (если у нас нету многопоточности, то блокировки нам всё равно не нужны, правильно?).
foreach (SomeObject o in Get()) { Dispatcher.Invoke(() => Process(o)); }
Если в методе Process будет браться та же блокировка, у вас будет взаимная блокировка, и код зависнет: Process будет дожидаться отпускания блокировки, а блокирующий код — возвращения из yield (то есть, следующей итерации цикла).

Комментариев нет:

Отправить комментарий