Подтвердить что ты не робот

Безопасно ли использовать ReaderWriterLockSlim в асинхронном методе

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

Например.

    System.Threading.ReaderWriterLockSlim readerwriterlock = new System.Threading.ReaderWriterLockSlim();
    private async Task Test()
    {
        readerwriterlock.EnterWriteLock();
        await Task.Yield(); //do work that could yield the task
        readerwriterlock.ExitWriteLock(); //potentailly exit the lock on a different thread
    }
4b9b3361

Ответ 1

Можно ли использовать ReaderWriterLockSlim в асинхронном методе

Да и нет. Это может быть безопасно использовать в методе async, но, вероятно, небезопасно использовать его в методе async, где вы вводите и выходите из блокировки, охватывающей await.

В этом случае нет, это не обязательно безопасно.

ExitWriteLock должен вызываться из того же потока, который называется EnterWriteLock. В противном случае он выбрасывает SynchronizationLockException. Из документации это исключение вызывается, если:

Текущий поток не вступил в блокировку в режиме записи.

Единственное время, когда это было бы безопасно, - это то, что это было использовано в методе async, который всегда находился в среде, где был текущий SynchronizationContext, который будет перемещать вещи обратно в один и тот же поток (то есть: Windows Forms, WPF и т.д.) И не использовался вложенным асинхронным вызовом, где "родительский" вызов цепочки вызовов настраивает задачу с ConfigureAwait(false) (что предотвратит захват Task контекста синхронизации). Если вы находитесь в этом конкретном сценарии, вы знаете, что поток будет поддерживаться, так как вызов await приведет вас к возврату в вызывающий контекст.

Ответ 2

Нет. Нитевидные координационные примитивы не должны использоваться как в вашем примере.

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

ReaderWriterLockSlim по умолчанию является нерекурсивной блокировкой, поэтому, если другой метод async пытается выполнить одну и ту же блокировку, вы получите тупик. Даже если вы сделаете блокировку рекурсивной, вы все равно столкнетесь с проблемой: произвольный код конечного пользователя никогда не должен вызываться, удерживая блокировку, и это, по сути, то, что вы делаете, когда используете await.

Тип SemaphoreSlim async -aware (через метод WaitAsync), а у Stephen Toub библиотеке AsyncEx.