如何使用 async/await 模式同步共享资源

How to synchronize shared resources with async/await pattern

我正在开发一些本质上是 pub/sub 框架的软件。

关于订阅,我必须记录订阅的内容,并且我需要进行订阅和取消订阅的原子操作。连接由 guid 标识,并且可以有多个订阅(例如,Alice 想要 NEWS 和 WEATHER)。因此,一旦爱丽丝与某个 ID 建立了联系,她就可以 Subscribe() 多次关注她关心的事件。

简单来说,我的订阅是这样的:

ConcurrentDictionary<string, List<string>> _subscriptionsForConnection;
async Task Subscribe()
{
   List<string> subscriptikons = _subscriptionsForConnection.GetOrAdd(connectionId, MakeNewList);
   await underlyingComponentA.SubscribeAsync(xxx);
   subscriptions.Add(xxx);
   await underlyingComponentB.SubscribeAsync(xxx);
}

问题是,我需要同步字典以确保订阅和取消订阅操作不会以订阅列表最终无法准确表示订阅状态的方式重叠。

从概念上讲,我想要以下内容:

lock(_subscriptionsForconnection)
{
    subscriptions = GetOrAdd();
    await SubscribeA();
    subscriptions.Add();
    await SubscribeB();
}

但是,出于多种原因,.net 4.5 不允许您在 lock 中包含 await,包括您的执行可能会在另一个上下文中恢复,从而无法解锁。 (这意味着 Monitor.Enter/Exit 将不起作用)。

另一种方法是序列化两个底层组件调用并使用Wait() 方法使它们同步运行,但这似乎是错误的。

我想我可能对这个问题的想法是错误的,所以我欢迎您的建议。

其他详细信息 我从我的解释中提取了一些细节以使其更清楚。对于那些想知道的人。 - 我正在 SignalR 之上开发一个组件。 underlyingComponentB.SubscribeAsync 实际上是 Groups.Add 调用。 - underlyingComponentA.SubscribeAsync 是将驱动我的组件的外部消息总线

使用SemaphoreSlim.WaitAsync代替lock