本文翻译自:Why can't I use the 'await' operator within the body of a lock statement?

The await keyword in C# (.NET Async CTP) is not allowed from within a lock statement. 锁定语句中不允许使用C#(.NET Async CTP)中的await关键字。

From MSDN : 从MSDN :

An await expression cannot be used in a synchronous function, in a query expression, in the catch or finally block of an exception handling statement, in the block of a lock statement , or in an unsafe context. 等待表达式不能用于同步函数,查询表达式,异常处理语句的catch或finally块, 锁语句的块或不安全的上下文中。

I assume this is either difficult or impossible for the compiler team to implement for some reason. 我认为由于某种原因,对于编译器团队而言,这既困难又不可能。

I attempted a work around with the using statement: 我尝试了using语句:

class Async
{public static async Task<IDisposable> Lock(object obj){while (!Monitor.TryEnter(obj))await TaskEx.Yield();return new ExitDisposable(obj);}private class ExitDisposable : IDisposable{private readonly object obj;public ExitDisposable(object obj) { this.obj = obj; }public void Dispose() { Monitor.Exit(this.obj); }}
}// example usage
using (await Async.Lock(padlock))
{await SomethingAsync();
}

However this does not work as expected. 但是,这无法正常工作。 The call to Monitor.Exit within ExitDisposable.Dispose seems to block indefinitely (most of the time) causing deadlocks as other threads attempt to acquire the lock. 在ExitDisposable.Dispose中对Monitor.Exit的调用似乎无限期地(大部分时间)阻塞,导致死锁,因为其他线程试图获取该锁。 I suspect the unreliability of my work around and the reason await statements are not allowed in lock statement are somehow related. 我怀疑我的工作不可靠,而锁语句中不允许使用await语句的原因与某种原因有关。

Does anyone know why await isn't allowed within the body of a lock statement? 有谁知道为什么锁语句体内不允许等待?


#1楼

参考:https://stackoom.com/question/VwNu/为什么不能在lock语句的主体内使用-await-运算符


#2楼

This referes to http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx , http://winrtstoragehelper.codeplex.com/ , Windows 8 app store and .net 4.5 这referes到http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx , http://winrtstoragehelper.codeplex.com/ ,Windows 8应用商店和.NET 4.5

Here is my angle on this: 这是我的看法:

The async/await language feature makes many things fairly easy but it also introduces a scenario that was rarely encounter before it was so easy to use async calls: reentrance. 异步/等待语言功能使很多事情变得相当容易,但是它也引入了一种在使用异步调用如此容易之前很少遇到的场景:重入。

This is especially true for event handlers, because for many events you don't have any clue about whats happening after you return from the event handler. 对于事件处理程序尤其如此,因为对于许多事件,从事件处理程序返回后,您对发生的事情一无所知。 One thing that might actually happen is, that the async method you are awaiting in the first event handler, gets called from another event handler still on the same thread. 实际上可能发生的一件事是,您在第一个事件处理程序中等待的async方法是从仍在同一线程上的另一个事件处理程序调用的。

Here is a real scenario I came across in a windows 8 App store app: My app has two frames: coming into and leaving from a frame I want to load/safe some data to file/storage. 这是我在Windows 8 App Store应用程序中遇到的一个真实场景:我的应用程序有两个框架:进入和离开一个框架我要加载/保护一些数据到文件/存储。 OnNavigatedTo/From events are used for the saving and loading. OnNavigatedTo / From事件用于保存和加载。 The saving and loading is done by some async utility function (like http://winrtstoragehelper.codeplex.com/ ). 保存和加载是通过一些异步实用程序功能(例如http://winrtstoragehelper.codeplex.com/ )完成的。 When navigating from frame 1 to frame 2 or in the other direction, the async load and safe operations are called and awaited. 从第1帧导航到第2帧或从其他方向导航时,将调用并等待异步加载和安全操作。 The event handlers become async returning void => they cant be awaited. 事件处理程序变为异步,返回void =>,无法等待它们。

However, the first file open operation (lets says: inside a save function) of the utility is async too and so the first await returns control to the framework, which sometime later calls the other utility (load) via the second event handler. 但是,该实用程序的第一个文件打开操作(在保存函数中说:)也是异步的,因此第一个await将控制权返回给框架,该控件稍后有时会通过第二个事件处理程序调用另一个实用程序(加载)。 The load now tries to open the same file and if the file is open by now for the save operation, fails with an ACCESSDENIED exception. 加载现在尝试打开同一文件,并且如果该文件现在已打开以进行保存操作,则加载失败,并出现ACCESSDENIED异常。

A minimum solution for me is to secure the file access via a using and an AsyncLock. 对我来说,最小的解决方案是通过使用和AsyncLock保护文件访问。

private static readonly AsyncLock m_lock = new AsyncLock();
...using (await m_lock.LockAsync())
{file = await folder.GetFileAsync(fileName);IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);using (Stream inStream = Task.Run(() => readStream.AsStreamForRead()).Result){return (T)serializer.Deserialize(inStream);}
}

Please note that his lock basically locks down all file operation for the utility with just one lock, which is unnecessarily strong but works fine for my scenario. 请注意,他的锁基本上只用一个锁就可以锁定该实用程序的所有文件操作,这虽然不必要,但对我的情况来说效果很好。

Here is my test project: a windows 8 app store app with some test calls for the original version from http://winrtstoragehelper.codeplex.com/ and my modified version that uses the AsyncLock from Stephen Toub http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx . 这是我的测试项目:Windows 8应用程序商店应用程序,其中一些测试调用来自http://winrtstoragehelper.codeplex.com/的原始版本,以及经过修改的版本,该版本使用来自Stephen Toub http://blogs.msdn的AsyncLock 。 com / b / pfxteam / archive / 2012/02/12 / 10266988.aspx 。

May I also suggest this link: http://www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitives.aspx 我也可以建议以下链接: http : //www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitives.aspx


#3楼

Hmm, looks ugly, seems to work. 嗯,看起来很丑,似乎可以工作。

static class Async
{public static Task<IDisposable> Lock(object obj){return TaskEx.Run(() =>{var resetEvent = ResetEventFor(obj);resetEvent.WaitOne();resetEvent.Reset();return new ExitDisposable(obj) as IDisposable;});}private static readonly IDictionary<object, WeakReference> ResetEventMap =new Dictionary<object, WeakReference>();private static ManualResetEvent ResetEventFor(object @lock){if (!ResetEventMap.ContainsKey(@lock) ||!ResetEventMap[@lock].IsAlive){ResetEventMap[@lock] =new WeakReference(new ManualResetEvent(true));}return ResetEventMap[@lock].Target as ManualResetEvent;}private static void CleanUp(){ResetEventMap.Where(kv => !kv.Value.IsAlive).ToList().ForEach(kv => ResetEventMap.Remove(kv));}private class ExitDisposable : IDisposable{private readonly object _lock;public ExitDisposable(object @lock){_lock = @lock;}public void Dispose(){ResetEventFor(_lock).Set();}~ExitDisposable(){CleanUp();}}
}

#4楼

Use SemaphoreSlim.WaitAsync method. 使用SemaphoreSlim.WaitAsync方法。

 await mySemaphoreSlim.WaitAsync();try {await Stuff();} finally {mySemaphoreSlim.Release();}

#5楼

Stephen Taub has implemented a solution to this question, see Building Async Coordination Primitives, Part 7: AsyncReaderWriterLock . Stephen Taub实现了此问题的解决方案,请参阅构建异步协调基元,第7部分:AsyncReaderWriterLock 。

Stephen Taub is highly regarded in the industry, so anything he writes is likely to be solid. Stephen Taub在该行业中享有很高的声誉,因此他撰写的任何文章都可能很扎实。

I won't reproduce the code that he posted on his blog, but I will show how to use it: 我不会复制他在博客上发布的代码,但是我将展示如何使用它:

/// <summary>
///     Demo class for reader/writer lock that supports async/await.
///     For source, see Stephen Taub's brilliant article, "Building Async Coordination
///     Primitives, Part 7: AsyncReaderWriterLock".
/// </summary>
public class AsyncReaderWriterLockDemo
{private readonly IAsyncReaderWriterLock _lock = new AsyncReaderWriterLock(); public async void DemoCode(){           using(var releaser = await _lock.ReaderLockAsync()) { // Insert reads here.// Multiple readers can access the lock simultaneously.}using (var releaser = await _lock.WriterLockAsync()){// Insert writes here.// If a writer is in progress, then readers are blocked.}}
}

If you a method that's baked into the .NET framework, use SemaphoreSlim.WaitAsync instead. 如果您将方法嵌入到.NET框架中,请改用SemaphoreSlim.WaitAsync You won't get a reader/writer lock, but you will get tried and tested implementation. 您不会获得读取器/写入器锁,但是将获得经过实践检验的实现。


#6楼

I did try using a Monitor (code below) which appears to work but has a GOTCHA... when you have multiple threads it will give... System.Threading.SynchronizationLockException Object synchronization method was called from an unsynchronized block of code. 我确实尝试使用似乎可以工作但具有GOTCHA的Monitor(下面的代码)...当您有多个线程时,它将给出... System.Threading.SynchronizationLockException对象同步方法是从未同步的代码块中调用的。

using System;
using System.Threading;
using System.Threading.Tasks;namespace MyNamespace
{public class ThreadsafeFooModifier : {private readonly object _lockObject;public async Task<FooResponse> ModifyFooAsync(){FooResponse result;Monitor.Enter(_lockObject);try{result = await SomeFunctionToModifyFooAsync();}finally{Monitor.Exit(_lockObject);}return result;}}
}

Prior to this I was simply doing this, but it was in an ASP.NET controller so it resulted in a deadlock. 在此之前,我只是这样做,但是它在ASP.NET控制器中,因此导致了死锁。

public async Task<FooResponse> ModifyFooAsync() { lock(lockObject) { return SomeFunctionToModifyFooAsync.Result; } }

为什么不能在lock语句的主体内使用#39;await#39;运算符?相关推荐

  1. 推荐的版本 lock 语句(C# 参考)

    最近在研究.NET分布式缓存代码,正好涉及Lock,看了网上的文章,总结了一些Lock相关的知识,供大家一起学习参考. 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被其 ...

  2. c#语法之lock 语句

    lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁.此语句的形式如下: Object thisLock = new Object(); lock (thisLoc ...

  3. java面试题41 下面字段声明中哪一个在interface主体内是合法的? ()

    java面试题41 下面字段声明中哪一个在interface主体内是合法的? () A private final static int answer = 42; B public static in ...

  4. java用while循环语句输出1-100内的奇数和

    java用while循环语句输出1-100内的奇数和 /*** 用while语句,输出0-100所有奇数和*/ public class Test04 {public static void main ...

  5. 如何通过SQL Server语句查询三个月内的信息代码的教程方法

    如何通过SQL Server语句查询三个月内的信息代码的教程方法 作者:张国军_Suger 开发工具与关键技术:SQL Server 2014.SQL.SQL关键字         由于需求需要我们达 ...

  6. c语言switch语句支持的字符有哪些,C语言中switch()语句的括号内可以是什么型别的呢?...

    C语言中switch()语句的括号内可以是什么型别的呢?以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! C语言中swit ...

  7. Python 循环语句和字符串内置函数

    系列文章目录 第五章 Python 机器学习入门之循环语句与字符串内置函数 Python 机器学习入门之循环语句 系列文章目录 前言 一.while 二.while嵌套循环 三.掷骰子 四.break ...

  8. lock语句和线程安全

    --------------以下部分内容摘自<C#高级编程(第八版)>--------------- 先来看一个简单的Demo: 首先是两个类的定义 Student类,只有一个简单的Num ...

  9. 一条批处理语句ping局域网内的所有机器

    执行语句: FOR /L %I in (1,1,255) DO PING 10.0.0.%I -n 1 -w 100 >> pung.txt 说明: FOR /L %I in (1,1,2 ...

最新文章

  1. postgresql-9.3.0级联复制搭建及简单配置
  2. python简单代码编写-Python | 编写一个简单的Excel处理脚本
  3. invester is the person whose opinion is so valuable
  4. 网上商城—管理员删除商品
  5. HBase集群安装部署(完全分布式)
  6. sql两个表查不同数据_产品操作MySQL第6篇 – 数据过滤-WHERE子句
  7. P4542-[ZJOI2011]营救皮卡丘【费用流,Floyd】
  8. B22-SVN在iOS开发的使用中遇到的问题
  9. nginx学习.第一部分
  10. uniapp实现滑动导航
  11. 3.5 数值分析: 例题及迭代法收敛的充分条件
  12. 官网Tomcat下载方法(亲测)
  13. Type-C PD协议取电SINK受电端9V12V15V20V
  14. 高德地图基本开发流程
  15. debug命令(debug命令的使用)
  16. 再生龙移植ubuntu硬盘大小限制解决方案
  17. Oracle 常用 语句
  18. python 词云 教程
  19. 不知不觉自己的C盘越来越大了?你可能需要看一看这个
  20. 免费赠送BTC和iPhone XS 揭开YEX虚拟盘的面纱

热门文章

  1. MUI框架开发HTML5手机APP(一)--搭建第一个手机APP
  2. 跟屌丝大哥学DB2-第四课 数据类型 ,表 ,视图,索引,模式,约束(一)
  3. xhtml、html与html5的区别
  4. Centos 6.4 ossec批量安装部署客户端
  5. 一些散落各处的移动开发好资源
  6. 参数展示初始三层架构
  7. Visio画UML图基本操作及技巧解析
  8. 提示No input file specified的解决方法
  9. VLC-3.0.0(Nightly版)在Linux和Windows下的编译步骤详解
  10. [ An Ac a Day ^_^ ] CodeForces 680A Bear and Five Cards