c# - 为什么我不能在 lock 语句的主体中使用 'await' 运算符?

标签 c# .net async-await

不允许在 lock 语句中使用 C#(.NET Async CTP)中的 await 关键字。

来自 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.

我认为由于某种原因,编译器团队很难或不可能实现这一点。

我尝试使用 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();
}

然而,这并没有像预期的那样工作。在 ExitDisposable.Dispose 中对 Monitor.Exit 的调用似乎无限期地(大部分时间)阻塞,导致死锁,因为其他线程试图获取锁。我怀疑我的变通方法的不可靠性与 lock 语句中不允许使用 await 语句的原因有某种关联。

有谁知道为什么 await 不允许出现在 lock 语句中?

最佳答案

I assume this is either difficult or impossible for the compiler team to implement for some reason.

不,实现起来一点也不困难或不可能 - 您自己实现的事实证明了这一事实。相反,这是一个非常糟糕的主意,因此我们不允许这样做,以防止您犯下这个错误。

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. I suspect the unreliability of my work around and the reason await statements are not allowed in lock statement are somehow related.

正确,您已经发现我们为什么将其定为非法。 在锁内等待是产生死锁的秘诀。

我相信您能明白原因:在 await 将控制权返回给调用者和方法恢复之间运行任意代码。该任意代码可能会取出产生锁顺序反转的锁,从而导致死锁。

更糟的是,代码可能会在另一个线程上恢复(在高级场景中;通常您会在执行等待的线程上再次启动,但不一定)在这种情况下,解锁将解锁一个锁在与取出锁的线程不同的线程上。这是一个好主意吗?没有。

我注意到,出于同样的原因,在 lock 中执行 yield return 也是“最糟糕的做法”。这样做是合法的,但我希望我们把它定为非法。我们不会对“等待”犯同样的错误。

关于c# - 为什么我不能在 lock 语句的主体中使用 'await' 运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7612602/

相关文章:

.net - WPF Datagrid 中的网格线着色

.net - 生产中 .NET 应用程序的持续性能监控?

javascript - Socket.io 和 Async 不返回值

c# - C#是否可以将基类的实例用于子类的不同实例?

c# - 通过触发器更改文本 block 中文本的颜色

c# - Windows 服务还是控制台应用程序?

JavaScript 递归返回一个从 Unresolved promise

c# - 如何判断列表是否不包含元素?

.net - 通过 IIS 访问文件服务器上的文件

javascript - Node 异步库 filterLimit 总是返回 undefined