Tôi gặp rắc rối với Haskell bracket
: Khi được chạy bên trong một đối số thứ hai (sử dụng forkFinally
) bracket
đối số thứ hai, tính toán giải phóng tài nguyên không chạy khi chương trình kết thúc.
Đây là mã minh họa vấn đề (Tôi biết rằng trong trường hợp cụ thể này, tôi có thể vô hiệu hóa bộ đệm để ghi vào tệp ngay lập tức):
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
Tính toán giải phóng tài nguyên (và ghi vào bàn điều khiển) không bao giờ được gọi là:
putStrLn $ "\nClosing handle " ++ show fileHandle
hClose fileHandle
Làm cho chương trình đơn luồng bằng cách loại bỏ mã forking main
khỏi vấn đề và xử lý tệp bị đóng khi kết thúc chương trình với Ctrl+ c:
main = writeToFile "first_file"
Làm thế nào để tôi đảm bảo rằng mã giải phóng tài nguyên bracket
được thực thi khi sử dụng nhiều luồng?
threadDelay
trước khi in"Closing handle"
.)