MVar Problem (Concurrent Hugs)
Dean Herington
heringto@cs.unc.edu
Fri, 18 May 2001 10:30:38 -0400
Andreas Gruenbacher wrote:
> Hello,
>
> I was trying to write an abstraction for bidirectional communication
> between two threads. For some reason, MVars seem to break:
>
> -----------------------------------------------
> class Cords c t u where
> newCord :: IO (c t u)
> listen :: c t u -> IO t
> speak :: c t u -> u -> IO ()
>
> data Cord t u = Cord (IO (MVar t)) (IO (MVar u))
>
> instance Cords Cord t u where
> newCord = return (Cord newEmptyMVar newEmptyMVar)
> speak (Cord _ s) t = do s' <- s ; putMVar s' t
> listen (Cord h s) = do h' <- h ; takeMVar h'
>
> otherEnd (Cord t u) = Cord u t
>
> showT :: Cord Int String -> IO ()
> showT cord = do
> putStrLn "Runnning..."
> x <- listen cord
> putStrLn ("Heard " ++ show x)
> speak cord (show x)
> putStr ("Said " ++ (show x))
> showT cord
>
> main :: IO ()
> main = do
> cord <- newCord
> forkIO (showT (otherEnd cord))
> speak cord 1
> str <- listen cord
> putStrLn str
> -----------------------------------------------
You are creating a new MVar with each listen and speak. As a result, the
two threads never agree on an MVar, so deadlock occurs. Instead, you should
create the pair of MVars in newCord. Try the code below.
> import Concurrent
> class Cords c t u where
> newCord :: IO (c t u)
> listen :: c t u -> IO t
> speak :: c t u -> u -> IO ()
> data Cord t u = Cord (MVar t) (MVar u)
> instance Cords Cord t u where
> newCord = do t <- newEmptyMVar
> u <- newEmptyMVar
> return (Cord t u)
> listen (Cord t _) = takeMVar t
> speak (Cord _ u) s = putMVar u s
> otherEnd (Cord t u) = Cord u t
> showT :: Cord Int String -> IO ()
> showT cord = do
> putStrLn "Runnning..."
> x <- listen cord
> putStrLn ("Heard " ++ show x)
> speak cord (show x)
> putStrLn ("Said " ++ show x)
> showT cord
> main :: IO ()
> main = do
> cord <- newCord
> forkIO (showT (otherEnd cord))
> speak cord 1
> str <- listen cord
> putStrLn str
Dean