Tengo problemas con Haskell bracket
: cuando se ejecuta dentro de un hilo bifurcado (usando forkFinally
) bracket
el segundo argumento, el cálculo que libera recursos no se ejecuta cuando finaliza el programa.
Aquí hay un código que ilustra el problema (soy consciente de que en este caso específico podría deshabilitar el almacenamiento en búfer para escribir en el archivo de inmediato):
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
El cálculo que libera recursos (y escribe en la consola) nunca se llama:
putStrLn $ "\nClosing handle " ++ show fileHandle
hClose fileHandle
Al hacer que el programa main
tenga un solo subproceso al eliminar el código de bifurcación, se elimina el problema y el identificador de archivo se cierra al finalizar el programa con Ctrl+ c:
main = writeToFile "first_file"
¿Cómo me aseguro de que el código de liberación de recursos bracket
se ejecute al usar varios subprocesos?
threadDelay
antes de imprimir"Closing handle"
.)