我有一个应用程序,其中有一个可由多个客户端访问的共享资源(Motion系统)。我有一些单独的操作需要在移动期间访问系统,如果同时请求冲突的操作,则会引发"繁忙"异常。我还有序列器,它需要获得对运动系统的独占访问权限,以执行几个操作,并穿插其他操作;在整个序列中,任何其他客户端都不应该能够运行操作。
传统上,我使用线程关联来处理此问题,这样线程就可以请求独占访问并运行与操作相对应的阻塞调用。当线程具有访问权限时,任何其他线程都不能使用该资源。我现在遇到的问题是,我已经转向使用异步/等待模式来实现我的系统,以允许更干净的序列器实现。问题是现在我的定序器并不总是在同一个线程上运行;活动线程在回调过程中可能会发生变化,因此不再容易确定我是否处于有效的上下文中以继续运行操作。需要注意的一点是,一些操作本身由等待组成,这意味着序列和单个操作都可以跨越多个线程。
我的问题是:有人知道在异步/等待导致线程切换的情况下获得独占访问的好模式吗?
作为参考,我考虑了一些事情:
-
我可以创建一个自定义SynchronizationContext,它将序列持续时间内的所有序列器调用封送回单个线程。这样做的好处是允许我重用现有的线程关联访问管理代码。缺点是,每当我执行序列或操作时,这将需要专用一个线程(因为操作也可以跨越多个线程)
-
创建一个可获取的访问令牌以传递给Operation方法,以证明您已获取访问权限。这有一个缺点,即使用令牌参数夸大方法。
-
使用(2)中的访问令牌方法,但为Operations接口创建一个重复的接口实现,以便可以使用令牌"烘焙"实例化包装器。这会创建一些丑陋的粘合代码,但它会清理定序器代码,这样它就不再需要向每个方法传递令牌。
我的问题是:有人知道在由于async/await导致的线程切换的情况下获得独占访问的好模式吗?
是的,您可以使用AsyncLock
,它也是我的AsyncEx库的一部分。如果你想有一个"TryLock"类型的操作,那么你可能必须创建自己的基元。
您确实失去了一些进行安全检查的能力:无法检查当前执行的线程是否具有特定的AsyncLock
。
其他选项包括ConcurrentExclusiveSchedulerPair
(我在这里写博客)或TPL数据流。
这里有SemaphoreSlim.WaitAsync
。(我在一个类似的问题中找到了它)。