2013-11-19 3 views
9

Я не понимаю (и не могу найти документацию достаточно ясно): при использовании ключевого слова lock в методе async: будет ли поток заблокирован, если объект уже заблокирован или он вернет задачу в приостановленном состоянии (не блокируя поток и возвращающийся при освобождении блокировки)?C# Lock and Async Method

В приведенном ниже коде будет ли линия перекрывать нить? Если он блокирует поток (это то, что я думаю), существует ли стандартное не блокирующее решение? Я рассматриваю использование AsyncLock, но сначала я хотел попробовать что-то стандартное.

спасибо.

private object myLock = new object(); 

private async Task MyMethod1(){ 
    lock (myLock) {// <---- will this line cause a return of the current method as an Await method call would do if myLock was already locked. 

    .... 
    } 
} 

// other methods that lock on myLock 
+2

Посмотрите здесь для хорошего объяснения HTTP: // StackOverflow ,com/questions/7612602/why-cant-i-use-the-wait-operator-in-the-body-of-a-lock-statement – atomaras

+1

Неверный ответ принят –

ответ

4

Нет, это не будет.

lock является синтаксическим сахаром для Monitor.Enter и Monitor.Exit. lock будет продолжать выполнение в методе до тех пор, пока блокировка не будет выпущена. Он не работает как await в любом случае, форме или форме.

+1

Спасибо. BTW: Я думаю, что применительно к моему вопросу: «Да, поток будет заблокирован», это ответ, который я ищу. – rufo

+1

Это правильно. –

+1

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

2

Задача не будет возвращена в приостановленном состоянии. Он будет ждать, пока myLock не будет разблокирован, чтобы запустить код в инструкции блокировки. Это произойдет независимо от того, какую асинхронную модель C# вы используете.

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

29

В приведенном ниже коде будет ли линия перекрывать нить?

Технически, да, но он не будет работать так, как вы ожидаете.

Есть две причины, по которым нито-аффинные блокировки плохо работают с async. Во-первых, (в общем случае) метод async может не возобновиться в одном потоке, поэтому он попытается освободить блокировку, которой он не владеет, в то время как другой поток удерживает блокировку навсегда. Другая причина заключается в том, что во время await, удерживая замок, произвольный код может выполняться во время блокировки.

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

Если он блокирует нить (что я думаю), существует ли стандартное не блокирующее решение?

Да; SemaphoreSlim поддерживает тип WaitAsync.

+1

Спасибо, что я вижу проблему, выполняющую 'await' в' lock'. Как насчет противоположности: используя 'lock' в методе, который в конечном итоге называется некоторым методом асинхронного вызова? Я предполагаю, что это безопасно, так как операция «блокировка» завершена в одном потоке. Тем не менее, использование мониторов напрямую кажется проблематичным в этом случае - но это отстой, потому что, как правило, разработчик не может определить, будет ли код использоваться в режиме async/await или нет. Что такое предложение? – KFL

+1

Пока в замке (или мониторе) есть только синхронный код, тогда он будет работать нормально. Не имеет значения, вызван ли он асинхронным методом или нет. –

4

Это было запрещено запрещать блокировку (то есть разработчики вредят себе). Лучшее решение я нашел использовать semaphones - Смотрите этот пост для деталей:

https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/

Соответствующий код экстракта:

static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); 

... 

await semaphoreSlim.WaitAsync(); 
try 
{ 
    await Task.Delay(1000); 
} 
finally 
{ 
    semaphoreSlim.Release(); 
}