使用 MVar 在线程之间进行通信
在 Control.Concurrent
中使用 MVar a
类型及其附带函数在线程之间传递信息非常容易:
newEmptyMVar::IO (MVar a)
- 创造一个新的MVar a
newMVar::a -> IO (MVar a)
- 创建一个具有给定值的新MVar
takeMVar::MVar a -> IO a
- 从给定的MVar
中检索值,或阻塞直到有一个可用putMVar::MVar a -> a -> IO ()
- 将给定值放入MVar
,或阻塞直到它为空
让我们在一个线程中将 1 到 1 亿的数字相加并等待结果:
import Control.Concurrent
main = do
m <- newEmptyMVar
forkIO $ putMVar m $ sum [1..10000000]
print =<< takeMVar m -- takeMVar will block 'til m is non-empty!
更复杂的演示可能是在等待更多输入时在后台获取用户输入和求和:
main2 = loop
where
loop = do
m <- newEmptyMVar
n <- getLine
putStrLn "Calculating. Please wait"
-- In another thread, parse the user input and sum
forkIO $ putMVar m $ sum [1..(read n::Int)]
-- In another thread, wait 'til the sum's complete then print it
forkIO $ print =<< takeMVar m
loop
如前所述,如果你调用 takeMVar
并且 MVar
是空的,它会阻塞,直到另一个线程将某些东西放入 MVar
,这可能会导致餐饮哲学家的问题 。同样的事情发生在 putMVar
:如果它已满,它会阻止’直到它是空的!
采取以下功能:
concurrent ma mb = do
a <- takeMVar ma
b <- takeMVar mb
putMVar ma a
putMVar mb b
我们用一些 MVar
s 运行这两个函数
concurrent ma mb -- new thread 1
concurrent mb ma -- new thread 2
可能发生的是:
- 线程 1 读取
ma
并阻止ma
- 线程 2 读取
mb
,因此阻止mb
现在线程 1 无法读取 mb
,因为线程 2 已阻止它,并且线程 2 无法读取 ma
,因为线程 1 阻止了它。经典的僵局!