我在处理Haskell的 以下代码说明了此问题(我知道在这种特定情况下,我可以禁用缓冲功能以立即写入文件): 从不释放资源(并写入控制台)的计算: 通过从 使用多个线程时,如何确保执行 答案 0 :(得分:5) 此问题的根本原因是,当 如果您想杀死线程但要强制清理线程,请像在此一样使用 答案 1 :(得分:5) 显然,用 我们可以使用bracket
时遇到麻烦:当在派生线程中运行(使用forkFinally
)@DslMarker
的第二个参数时,释放资源的计算在以下情况下不运行程序结束。bracket
import System.IO
import Control.Exception ( bracket
, throwTo
)
import Control.Concurrent ( forkFinally
, threadDelay
)
main = do
threadId <- forkFinally
(writeToFile "first_file")
(\ex -> putStrLn $ "Exception occurred: " ++ show ex)
putStrLn "Press enter to exit"
_ <- getLine
putStrLn "Bye!"
writeToFile :: FilePath -> IO ()
writeToFile file = bracket
(openFile file AppendMode)
(\fileHandle -> do
putStrLn $ "\nClosing handle " ++ show fileHandle
hClose fileHandle
)
(\fileHandle -> mapM_ (addNrAndWait fileHandle) [1 ..])
addNrAndWait :: Handle -> Int -> IO ()
addNrAndWait fileHandle nr =
let nrStr = show nr
in do
putStrLn $ "Appending " ++ nrStr
hPutStrLn fileHandle nrStr
threadDelay 1000000
putStrLn $ "\nClosing handle " ++ show fileHandle
hClose fileHandle
中删除派生代码来使程序成为单线程,可以解决此问题,并在使用 Ctrl + c结束程序时关闭文件句柄kbd>:main
main = writeToFile "first_file"
中的资源释放代码?2 个答案:
main
退出时,您的进程将终止。它不会等待您创建的任何其他线程来完成。因此,在您的原始代码中,您创建了一个线程来写入文件,但是不允许完成该线程。throwTo
。如果您希望线程完成,则需要等待main
返回之前。参见How to force main thread to wait for all its child threads finish in Haskell 使用
throwTo
bracket
创建的线程永远不会抛出异常,因此forkFinally
的资源释放代码也永远不会执行。bracket
手动完成此操作:throwTo threadId ThreadKilled