33

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

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

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

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

4

2 回答 2

4

您可以使用Control.Concurrent.MVar来实现这一点。AnMVar本质上是一个“空”或“满”的标志。一个线程可以尝试读取一个MVar,如果它是空的,它会阻塞线程。无论您在哪里有一个执行文件 IO 的线程,都为其创建一个MVar,并将其MVar作为参数传递。MVar将您创建的所有s 放入列表中:

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 

否则你的线程会退出,只要把所有的MVars.

有关更多详细信息,请参阅有关 GHC 并发的文档

于 2013-06-02T18:52:02.217 回答
3

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

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

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

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

于 2013-06-15T13:41:19.063 回答