我有一个使用多个线程的程序。据我了解,当线程0退出时,整个程序退出,无论其他任何可能仍在运行的线程。
问题是,这些其他线程可能有文件打开。当然,这包含在异常处理代码中,以便在出现问题时干净地关闭文件。这也意味着如果我使用killThread
(通过throwTo
实现),该文件应该在线程退出之前也关闭。
我的问题是,如果我让线程0退出,而不试图阻止其他线程,那么各种文件句柄是否会被很好地关闭?是否刷新了任何缓冲的输出?
简而言之,我可以退出,还是首先需要手动杀死线程?
答案 0 :(得分:3)
您可以使用Control.Concurrent.MVar
来实现此目的。 MVar
本质上是一个“空”或“满”的标志。线程可以尝试读取MVar
,如果它是空的,它会阻塞线程。只要有一个执行文件IO的线程,就为它创建一个MVar
,并将MVar
作为参数传递给它。将您创建的所有MVar
放入列表中:
main = do
let mvars = sequence (replicate num_of_child_threads newEmptyMVar)
returnVals <- sequence (zipWith (\m f -> f m)
mvars
(list_of_child_threads :: [MVar -> IO a]))
一旦子线程完成了您担心的所有文件操作,请写入MVar
。而不是写killThread
你可以做
mapM_ takeMVar mvars >> killThread
并且无论你的线程在哪里退出,只需要取出所有MVar
s。
有关详细信息,请参阅documentation on GHC concurrency。
答案 1 :(得分:3)
从我的测试中,我发现了一些事情:
exitFailure
和朋友只能在线程0中工作。(文档实际上是这样说的,如果你去阅读它的麻烦。这些函数只是抛出异常,在其他线程中被忽略。 )
如果异常导致您的线程或整个程序被杀死,则任何打开的句柄都不会 刷新。当你拼命想弄清楚你的程序崩溃的位置时,这非常令人烦恼!
因此,如果您希望在程序退出之前刷新您的内容,那么您必须实现此功能。只是让线程0死不会刷新东西,不抛出任何异常,只是默默地终止所有线程而不运行异常处理程序。