退出Haskell计划的最佳方法是什么?

时间:2013-06-01 12:50:49

标签: multithreading haskell

我有一个使用多个线程的程序。据我了解,当线程0退出时,整个程序退出,无论其他任何可能仍在运行的线程。

问题是,这些其他线程可能有文件打开。当然,这包含在异常处理代码中,以便在出现问题时干净地关闭文件。这也意味着如果我使用killThread(通过throwTo实现),该文件应该在线程退出之前关闭。

我的问题是,如果我让线程0退出,而不试图阻止其他线程,那么各种文件句柄是否会被很好地关闭?是否刷新了任何缓冲的输出?

简而言之,我可以退出,还是首先需要手动杀死线程?

2 个答案:

答案 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)

从我的测试中,我发现了一些事情:

  1. exitFailure和朋友只能在线程0中工作。(文档实际上是这样说的,如果你去阅读它的麻烦。这些函数只是抛出异常,在其他线程中被忽略。 )

  2. 如果异常导致您的线程或整个程序被杀死,则任何打开的句柄都不会 刷新。当你拼命想弄清楚你的程序崩溃的位置时,这非常令人烦恼!

  3. 因此,如果您希望在程序退出之前刷新您的内容,那么必须实现此功能。只是让线程0死不会刷新东西,不抛出任何异常,只是默默地终止所有线程而不运行异常处理程序。