使用 async/await 锁定资源
Posted
技术标签:
【中文标题】使用 async/await 锁定资源【英文标题】:Resource locking with async/await 【发布时间】:2012-09-23 13:28:54 【问题描述】:我有一个应用程序,其中有一个共享资源(运动系统),可以由多个客户端访问。我有个别操作需要在移动期间访问系统,如果同时请求冲突操作,则应该抛出“忙碌”异常。我也有 Sequencer,需要获得对 Motion 系统的独占访问权限以执行多个操作,并穿插其他操作;在整个序列中,没有其他客户端能够运行操作。
我传统上使用线程亲和性来解决这个问题,以便线程可以请求独占访问并运行与操作相对应的阻塞调用。虽然线程具有访问权限,但没有其他线程可以使用该资源。我现在遇到的问题是我已经转向使用 async/await 模式来实现我的系统,以允许更清晰的序列器实现。问题是现在我的定序器并不总是在同一个线程上运行;活动线程可以在回调过程中发生变化,因此不再容易确定我是否处于有效的上下文中以继续运行操作。需要注意的一点是,一些操作本身是由等待组成的,这意味着序列和单个操作都可以跨越多个线程。
我的问题:有人知道在由于 async/await 导致线程切换的情况下获取独占访问的好模式吗?
作为参考,我考虑了一些事情:
我可以创建一个自定义 SynchronizationContext,它将序列持续时间内的所有排序器调用编组回单个线程。这样做的好处是允许我重用现有的线程关联访问管理代码。不利的一面是,每当我执行序列或操作时,这都需要专用线程(因为操作也可以跨越多个线程。)
创建一个可获取的访问令牌以传递给操作方法,以证明您已获得访问权限。这具有使用令牌参数使方法膨胀的缺点。
使用 (2) 中的访问令牌方法,但为操作接口创建一个重复的接口实现,以便可以使用令牌“烘焙”来实例化包装器。这会创建一些丑陋的胶水代码,但它会清理序列器代码,因此不再需要将令牌传递给每个方法。
【问题讨论】:
【参考方案1】:我的问题:有人知道在由于 async/await 导致线程切换的情况下获取独占访问的好模式吗?
是的,您可以使用AsyncLock
,它也可作为我的AsyncEx library 的一部分使用。如果您想进行“TryLock”类型的操作,那么您可能必须创建自己的原语。
您确实失去了一些进行安全检查的能力:无法检查当前正在执行的线程是否具有特定的AsyncLock
。
其他选项包括ConcurrentExclusiveSchedulerPair
(我在博客中提到了here)或TPL Dataflow。
【讨论】:
我会将其标记为有用阅读的答案。我最终为包含访问检查的接口创建了代理。然后,我可以分发一个特殊的一次性“独占访问”代理,以防止其他代理实例在系统处于活动状态时使用该系统。【参考方案2】:SemaphoreSlim.WaitAsync
非常适合这里。
(我在a similar question 找到的)。
【讨论】:
以上是关于使用 async/await 锁定资源的主要内容,如果未能解决你的问题,请参考以下文章
异步编程之Async,Await和ConfigureAwait的关系