Haskell线程何时加入



作为一名前C++程序员,Haskell线程的行为令人困惑。请参阅以下Haskell代码片段:

import Control.Concurrent
import Control.Concurrent.MVar
import Data.Functor.Compose
import System.Random
randomTill0 :: MVar () -> IO () -- Roll a die until 0 comes
randomTill0 mV = do
x <- randomRIO (0,65535) :: IO Int
if 0 == x
then putMVar mV ()
else randomTill0 mV
main :: IO ()
main = do
n <- getNumCapabilities
mV <- newEmptyMVar
sequence (replicate n (forkIO (randomTill0 mV)))
readMVar mV
putStrLn "Excution complete."

据我所知,Haskell的forkIO大致相当于C++的std::async。在C++中,我存储一个std::future,它由std::async返回,然后是std::future::wait,然后线程将是std::thread::join

(关于消息之前的微小延迟,我认为这里不涉及任何懒惰。(

我的问题是:

  1. 在上面的Haskell代码片段中,forkIO产生的线程何时加入?是在readMVar mV,还是在main结束?

  2. 是否存在std::thread::detach的Haskell等价物?

据我所知,线程从不连接,程序在main结束时结束。这对于main来说是特殊的——通常线程在任何层次结构中都不会相互关联。加入线程的概念并不存在:线程一直运行,直到它的操作完成,或者直到它被killThread显式地杀死,然后它就蒸发了(谢谢,垃圾收集器(。如果你想等待线程完成,你必须自己完成,可能需要MVar

因此,detach没有类似物–所有线程都会自动分离。

另一件值得一提的事情是,OS线程和Haskell线程之间没有1:1的对应关系。Haskell运行时系统有自己的调度器,可以在单个操作系统线程上运行多个Haskell线程;一般来说,Haskell线程在其生命周期中会在不同的OS线程之间来回切换。有一个绑定线程的概念,它与操作系统线程绑定,但使用它的唯一原因是,如果您使用其他语言的代码来区分操作系统线程。

最新更新