在线程之间共享mvar

时间:2015-06-02 20:58:40

标签: multithreading haskell concurrency

我试图制作一个打印箭头的程序,直到用户按下回车键(参见下面的代码)。

问题是,当我按下回车键时,我会看到"停止"控制台中的字符串,但它不会在outputArrows函数中更改m的值。

我如何分享州?

import Control.Concurrent
import Control.Concurrent.Async
import Control.Monad

waitForInput m = do
    getLine
    putStrLn "stop"
    putMVar m True

outputArrows m = do
    stop <- readMVar m
    unless stop $ do
        threadDelay 1000000
        putStr ">"
        outputArrows m

main = do
    m <- newMVar False
    th1 <- async (waitForInput m)
    th2 <- async (outputArrows m)
    wait th1
    wait th2

2 个答案:

答案 0 :(得分:7)

您的putMVar实际上并没有在MVar中添加新值,而是无限期阻止。 MVar就像只能容纳一个值的盒子。如果要替换该值,则需要先取出旧值。

如果您不需要MVar的阻止行为,那么您应该使用常规IORef或可能TVar,如果您需要确保更复杂的操作以原子方式运行。

答案 1 :(得分:3)

您应该使用swapMVar代替putMVar。正如@shang所提到的那样,putMVar会阻塞,直到MVar为空,因此putMVar永远不会完成:

waitForInput m = do
    getLine
    putStrLn "stop"
    swapMVar m True

或者,您可以使用空MVar ()作为布尔标志:

waitForInput :: MVar () -> IO ()
waitForInput m = do
    getLine
    putStrLn "stop"
    putMVar m ()

outputArrows :: MVar () -> IO ()
outputArrows m = do
    running <- isEmptyMVar m
    when running $ do
        threadDelay 1000000
        putStr ">"
        outputArrows m

main :: IO ()
main = do
    hSetBuffering stdout NoBuffering
    m <- newEmptyMVar
    th1 <- async (waitForInput m)
    th2 <- async (outputArrows m)
    wait th1
    wait th2