Haskellで問題が発生しbracket
ています。フォークされたスレッド内で(forkFinally
)bracket
の2番目の引数を使用して実行すると、プログラムの終了時にリソースを解放する計算が実行されません。
問題を示すコードは次のとおりです(この特定のケースでは、バッファリングを無効にしてファイルにすぐに書き込むことができることを知っています)。
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
フォークコードを削除してプログラムをシングルスレッドにするmain
と、問題がなくなり、プログラムをCtrl+で終了するとファイルハンドルが閉じますc。
main = writeToFile "first_file"
bracket
複数のスレッドを使用しているときに、リソース解放コードが確実に実行されるようにするにはどうすればよいですか?
threadDelay
印刷する前にショートを追加することで競合状態を確認できます"Closing handle"
。)