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

Ath*_*ark 2 multithreading haskell asynchronous cancellation

有没有办法cancelasync异步包调用的线程中使用?我可以看到你可以从线程外部取消它,但我想知道是否有一个cancelSelf :: IO ()函数可以阻止它自己的执行.我可以使用唯一的id生成和线程引用的共享Map来组合一些东西Async,线程本身可以引用它,但这看起来太多了.我可以逃避未被捕获的异常或其他什么吗?

Car*_*arl 5

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

{-# LANGUAGE RecursiveDo #-}

import Control.Concurrent.Async

main :: IO ()
main = do
    rec let doCancel = cancel calculate
        calculate <- async doCancel
    wait calculate
Run Code Online (Sandbox Code Playgroud)

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

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

哦,for 的实现mfixIO是可怕的.我很高兴我不必自己写.

- 编辑 -

由于这几乎没有得到反馈,我已经意识到如何使用它来解决你的问题并不是很明显.所以这是一个扩展的例子,它使用组合器来产生一个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
Run Code Online (Sandbox Code Playgroud)