2017-05-08 169 views
0

我有一個函數將請求發送到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交易COMMITED後沒有異步異常可能會偷偷英寸但是,這當然不會編譯,因爲restoreIO a -> IO a,而不是STM a -> STM a

有沒有什麼辦法可以解除異步異常,僅用於我的STM事務?或者,也許另一種方式來保證異步異常到達,我的第一個STM事務中止或我的第一個STM事務提交,並且沒有異步異常可以終止我的線程,直到我爲它安裝處理程序onException

+0

爲什麼你想在這裏恢復異步異常?如果'requestPostSTM'分配資源,那麼它應該被屏蔽異步異常執行。請注意'原子'是可中斷的。 – Yuras

+0

'''requestPostSTM'''在內部寫入一個有界的chan並可能重試。也許這只是我的完美主義,但允許異步異常終止該事務似乎是合法的。 – Anton

+1

即使異步異常被屏蔽,那麼'STM'操作即重試將異步異常中止(如果有的話),請參閱https://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Exception .html#g:13 – Yuras

回答

1

最好將requestPostSTM稱爲異步異常屏蔽。所有STM重試的操作都是interruptible,所以它們將在異步異常情況下中止,但異常無法到達意外的位置。規則是:如果你的動作分配了資源(即某些東西應該被釋放),那麼你應該在屏蔽異步異常的情況下運行它,並且依靠可中斷的動作來中止某些已知點的動作(或者手動將異步異常通過allowInterrupt )。

+0

不知何故,我錯過了可中斷行爲的整個概念。這解決了我的問題,謝謝! – Anton