为什么没有类似Monitor.EnterAsync的方法

pg0*_*0xC 10 c#

我在新框架中看到许多方法,它们async/await在C#中使用新的异步模式/语言支持.为什么没有Monitor.EnterAsync()或其他async lock机制可以尽快释放当前线程并返回lock

我认为这是不可能的 - 问题是为什么?

Ren*_*ogt 5

我想问题是通过调用Monitor.Enter当前线程想要获得传递对象的锁。所以你应该问问自己你将如何实现Monitor.EnterAsync? 第一次天真的尝试是:

public async Task EnterAsync(object o)
{
    await Task.Run(() => Monitor.Enter(o));
}
Run Code Online (Sandbox Code Playgroud)

但这显然不符合您的预期,因为锁定将由为该新线程启动的线程获得,Task而不是由调用线程获得。
您现在需要一种机制来确保您可以在等待后获得锁定。但是我目前想不出如何确保这会起作用并且没有其他线程会在两者之间获得锁定的方法。


这些只是我的 2 美分(如果不是太长,就会作为评论发布)。我期待有更详细知识的人为您提供更启发性的答案。


Dav*_*aim 5

.Net 提供的一些同步原语是围绕底层本机对象的托管包装器。

目前,没有实现异步锁定的本机同步原语。所以 .Net 实现者必须从头开始实现,这并不像看起来那么简单。

此外,Windows 内核不提供任何“锁定-委托”功能,这意味着您无法在一个线程中锁定锁,并将所有权传递给另一个线程,这使得实现此类锁的工作变得非常困难。

在我看来,第三个原因更具哲学性——如果你不想阻塞——使用非阻塞技术,比如使用异步 IO、无锁算法和数据结构。如果您的应用程序的瓶颈是严重的争用和围绕它的锁定开销,您可以以不同的形式重新设计您的应用程序,而无需异步锁。


Ged*_*tis 5

虽然默认情况下 .NET中没有异步监视器,但Stephen Cleary具有出色的AsyncEx库,该库可在使用async / await时处理同步问题。

它有一个AsyncMonitor类,它几乎可以完全满足您的需求。您可以从GitHubNuGet包中获取它。

用法示例:

var monitor = new AsyncMonitor();
using (await monitor.EnterAsync())
{
    // Critical section
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*ary 5

我认为这是不可能的-问题是为什么?

有可能,它还没有完成。

当前,BCL中唯一的异步兼容同步原语是SemaphoreSlim,它可以充当信号灯或简单的互斥锁。

我有一个AsyncMonitor我写的基础知识,大致基于Stephen Toub的博客文章系列。请注意,语义与BCL略有不同Monitor;特别是,它不允许递归锁(由于我在博客中描述的原因)。