在STM事务中取消屏蔽异步异常
我有一个函数向STM通道发送请求,然后阻塞等待请求完成的线程。 如果我的阻塞线程被异步异常终止,那么我想发送取消请求到该STM通道。 它目前看起来像这样:
runRequest channel request = mask $ restore -> do
(reqId, resultVar) <- restore . atomically $ requestPostSTM channel request
onException
(restore . atomically $ do
maybeResult <- readTVar resultVar
case maybeResult of
Just x -> return x
Nothing -> retry)
(atomically $ requestCancelSTM channel reqId)
这几乎是我所需要的,但异常异常在requestPostSTM
事务成功后才会到达,但仍然在我们退出restore
块之前有一点小可能性。 如果发生这种情况,那么我会发布我的请求,但无法发布取消消息。
理想情况下,我想将第二行更改为类似的内容
(reqId, resultVar) <- atomically . restore $ requestPostSTM channel request
通过这种方式,我确信在requestPostSTM
事务提交之后,没有任何异步异常可以潜入。 但是,这当然不会编译,因为restore
是IO a -> IO a
,而不是STM a -> STM a
。
有没有什么办法可以在我的STM事务持续时间内揭露异步异常? 或者也许另一种方式来保证异步异常到达,我的第一个STM事务异常终止或我的第一个STM事务提交并且没有异步异常可以终止我的线程,直到我用onException
安装它的处理程序?
最好调用requestPostSTM
并屏蔽异步异常。 所有重试的STM
操作都是可中断的,所以它们将在异步异常情况下中止,但异常无法到达意外的地方。 规则是:如果你的动作分配了资源(即某些东西应该被释放),那么你应该在屏蔽异步异常的情况下运行它,并且依靠可中断的动作来中止某些已知点的动作(或者用allowInterrupt
手动allowInterrupt
异步异常)。