使用 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 阻止了它。經典的僵局!