32

我有一个应用程序,其中有一个共享资源(运动系统),可以由多个客户端访问。我有个别操作需要在移动期间访问系统,如果同时请求冲突操作,则应该抛出“忙碌”异常。我也有 Sequencer,需要获得对 Motion 系统的独占访问权限以执行多个操作,并穿插其他操作;在整个序列中,没有其他客户端应该能够运行操作。

我传统上使用线程关联来解决这个问题,以便线程可以请求独占访问并运行与操作相对应的阻塞调用。虽然线程具有访问权限,但没有其他线程可以使用该资源。我现在遇到的问题是我已经转向使用 async/await 模式来实现我的系统,以允许更清晰的序列器实现。问题是现在我的定序器并不总是在同一个线程上运行;活动线程可以在回调过程中发生变化,因此不再容易确定我是否处于有效的上下文中以继续运行操作。需要注意的一点是,一些操作本身是由等待组成的,这意味着序列和单个操作都可以跨越多个线程。

我的问题:有没有人知道一个很好的模式来处理由于异步/等待而在线程切换的情况下获取独占访问?

作为参考,我考虑了一些事情:

  1. 我可以创建一个自定义 SynchronizationContext,它将序列持续时间内的所有定序器调用编组回单个线程。这样做的好处是允许我重用现有的线程关联访问管理代码。不利的一面是,每当我执行序列或操作时,这都需要专用线程(因为操作也可以跨越多个线程。)

  2. 创建一个可获取的访问令牌以传递给 Operation 方法,以证明您已获得访问权限。这具有使用令牌参数使方法膨胀的缺点。

  3. 使用 (2) 中的访问令牌方法,但为操作接口创建一个重复的接口实现,以便可以使用令牌“烘焙”来实例化包装器。这会创建一些丑陋的胶水代码,但它会清理序列器代码,以便不再需要将令牌传递给每个方法。

4

2 回答 2

24

我的问题:有没有人知道一个很好的模式来处理由于异步/等待而在线程切换的情况下获取独占访问?

是的,您可以使用AsyncLock,它也作为我的AsyncEx 库的一部分提供。如果您想进行“TryLock”类型的操作,那么您可能必须创建自己的原语。

您确实失去了一些进行安全检查的能力:无法检查当前执行的线程是否具有特定的AsyncLock.

其他选项包括(我在这里ConcurrentExclusiveSchedulerPair写博客)或 TPL 数据流。

于 2012-10-02T17:05:29.607 回答
12

SemaphoreSlim.WaitAsync一个非常适合这里的。(我在一个类似的问题中找到了它)。

于 2015-11-16T13:02:10.690 回答