我目前正在使用以下代码来启动工作线程。
import Control.Monad (void)
import Control.Concurrent (forkIO)
import Control.Exception (finally)
import Data.IORef (newIORef, writeIORef, readIORef)
startWorker :: IO a -> IO (IO Bool)
startWorker work = do
running <- newIORef True
_ <- forkIO $ void work `finally` writeIORef running False
return $ readIORef running
即。开始在后台进行一些工作并返回一个IO动作,如果工作线程仍然在运行或由于某种原因它已经停止,则允许调用者轮询。
这种方法有多可靠?是否存在线程在不调用finally
块的情况下死亡的情况(当然,不包括整个过程被杀死的情况)?有没有更好的方法来实现相同的功能?
答案 0 :(得分:7)
异步异常可能在创建线程之后触发,但在&#34; void work`dinal`之前运行False&#34;开始了。使用forkFinally来处理。
答案 1 :(得分:5)
与Yuras相关&#39;回答,初始掩蔽状态可能存在一些问题,正如Simon Marlow的书Mask and forkIO section中所解释的那样。他解释说,底线是:
经验法则是,使用
forkIO
可以更好地编写forkFinally
中所谓的第一个异常处理函数。特别是,如果您发现自己最终forkIO (x
撰写y)
,请改写forkFinally x (\_ -> y)
。更好的是,使用Async API,它为您处理这些细节。