Sharing mvar between threads

I am trying to create a program that prints arrows until the user presses the enter button (see code below).

The problem is, when I hit enter, I see the line "stop" in the console, but it doesn't change the value of m in the outputArrows function.

How can I share my status?

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

      

+3


source to share


2 answers


Yours putMVar

does not actually put the new value in MVar

, but blocks indefinitely. MVars are like boxes that can only hold one value. If you want to replace a value, you must first take out the old value.



If you don't need to block the MVar behavior, you should just use the regular one, IORef

or perhaps TVar

if you need to make sure more complex operations are done atomically.

+7


source


You should use swapMVar

instead putMVar

. As @shang mentioned, it putMVar

blocks until MVar

empty, so it putMVar

never ends:

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

      



Alternatively, you can simply use empty MVar ()

as a boolean flag:

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

      

+3


source







All Articles