每篇有关异常的 Haskell 文章都重复简单的模式:使用括号函数分配/释放资源,您将是安全的。
我有一个担忧,因为我测试了它的行为并检测到线程在发布部分工作时会出现异步异常。
import Control.Exception
import Control.Concurrent
main = do
tid <- forkIO myThread
threadDelay 100000
throwTo tid StackOverflow
threadDelay 1000000
myThread =
bracket
(putStrLn "NEW")
(\() -> threadDelay 500000 >> putStrLn "CLEAN")
(\() -> putStrLn "USE")
在上面的代码片段中,由于异步异常而没有打印“CLEAN” - 所以资源泄漏!如何声称它是安全的?我不知道这一定是一个原因。
为了确保安全,我需要将每次清洁都包裹在 mask 内。它看起来很笨拙。
最佳答案
To make it safe as I see it I need to wrap every cleaning inside mask.
不幸的是,我认为答案正是如此。如果您有必须为资源安全而运行的清理操作,并且您希望通过异步异常来维护资源安全,那么您必须在清理期间使用不间断掩码。
这类似于将自己限制在 Unix/Linux 信号处理程序中的信号安全函数或 C++ 析构函数中的异常安全函数,除了这里的标准是“不可中断”,无论是您调用的函数所固有的,还是通过屏蔽(可能更容易获得正确的)。
或者,您可以使用
bracket
来自 unliftio
包,它在其清理处理程序中使用不间断屏蔽。 (与您的问题无关,此包提供了 MonadUnliftIO
类,用于通过无状态包装器提升 IO
操作;它是更复杂的 MonadBaseControl
的受限替代方案,来自 monad-control
,它处理任何基本 monad 上的有状态包装器。)
关于haskell - 如何使括号免受异步异常的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64468126/