从线程本身中取消异步线程

时间:2017-03-08 06:46:03

标签: multithreading haskell asynchronous cancellation

有没有办法在async包中使用async调用的线程中使用cancelSelf :: IO ()?我可以看到你可以从线程外部取消它,但我想知道是否有一个Map函数可以停止自己的执行。我可以使用唯一的id生成和共享Async <div class="row"> <div class="col-xs-2 col-xs-offset-5"></div> </div> col线程引用来组合一些东西,线程本身可以引用它,但这看起来太多了。我可以逃避未被捕获的异常或其他什么吗?

1 个答案:

答案 0 :(得分:5)

异步操作可以自行取消。不过,这涉及到一些技巧。

{-# LANGUAGE RecursiveDo #-}

import Control.Concurrent.Async

main :: IO ()
main = do
    rec let doCancel = cancel calculate
        calculate <- async doCancel
    wait calculate

从理论上讲,你可以在没有RecursiveDo的情况下做到这一点,但是我从来没有想过手写mfix表达式(RecursiveDo绑定到desugar)。

RecursiveDo允许您在do块内创建一个相互递归的定义集,即使某些定义与<-绑定,有些定义在let语句中定义。与往常一样,如果涉及真正的循环,计算将会发生分歧。但是在很多情况下你想要做的就是能够引用上面例子中的其他名称,RecursiveDo就可以了。

哦,the implementation of mfix for IO令人恐惧。我很高兴我自己也不必写它。

- 编辑 -

由于这几乎没有收到任何反馈,我已经意识到如何使用它来解决您的问题并不是很明显。所以这是一个扩展示例,它使用组合器生成可以取消自身的Async

{-# LANGUAGE RecursiveDo #-}

-- obviously want the async library
import Control.Concurrent.Async

-- used in selfCancelableAsync
import Control.Monad      (forever)
import Control.Concurrent (threadDelay)

-- only used for demonstration
import System.Random      (randomIO)

main :: IO ()
main = do
    a <- selfCancelableAsync $ \selfCancel -> do
        choice <- randomIO
        if choice then return "Success!" else selfCancel
    result <- wait a
    putStrLn result

-- spawns an Async that has the ability to cancel itself by
-- using the action passed to the IO action it's running
selfCancelableAsync :: (IO a -> IO b) -> IO (Async b)
selfCancelableAsync withCancel = do
    rec let doCancel = do
                cancel calculate
                -- This must never return to ensure it has the correct type.
                -- It uses threadDelay to ensure it's not hogging resources
                -- if it takes a moment to get killed.
                forever $ threadDelay 1000

        calculate <- async $ withCancel doCancel

    return calculate