Выбор ответа Middle Потоки и синхронизация спрашивают часто обновлено
await внутри lock
Вопрос
Почему такой код не компилируется и что использовать вместо него?
private readonly object _sync = new();
public async Task SaveAsync()
{
lock (_sync)
{
await _db.SaveChangesAsync();
}
}
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Правильный ответ: Монитор привязан к потоку, а после await поток другой: SemaphoreSlim. Monitor владеет потоком, который захватил блокировку.
Варианты ответа
lockнельзя использовать в async-методах вообще, даже безawait- Нужно заменить
lockнаMonitor.Enter, тогдаawaitразрешён - Нужно сделать
_syncстатическим полем, тогда монитор общий - Монитор привязан к потоку, а после
awaitпоток другой:SemaphoreSlimправильный ответ
Разбор
Monitor владеет потоком, который захватил блокировку. После await продолжение может попасть на другой поток, и освобождение от его имени невозможно, поэтому компилятор запрещает await в теле lock (CS1996). lock в async-методе допустим, если внутри нет await. Monitor.Enter вручную даёт ту же проблему, только без защиты компилятора. Асинхронный аналог: SemaphoreSlim(1, 1) с await WaitAsync() и Release() в finally.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.