
Hi everyone, I have a beginer question on using MVar. In the simple case I am getting what I expect... ***CODE*** module Main ( main ) where import Control.Concurrent import System.IO main = do mv <- newEmptyMVar putMVar mv 'a' threadDelay (5 * 10^6) putMVar mv 'b' threadDelay (5 * 10^6) ***/CODE*** Output after the first 5 second delay is :- Demo.exe: thread blocked indefinitely It even works as expected when there is a reading thread ***CODE*** module Main ( main ) where import Control.Concurrent import Control.Monad import System.IO main = do mv <- newEmptyMVar forkIO (readMV mv) putMVar mv 'a' threadDelay (5 * 10^6) putMVar mv 'b' threadDelay (5 * 10^6) readMV mv = forever $ do ch <- takeMVar mv putChar ch >> hFlush stdout ***/CODE*** Output including expected delays :- ab Then it starts to act unexpectedly ***CODE*** module Main ( main ) where import Control.Concurrent import Control.Monad import System.IO main = do mv <- newEmptyMVar forkIO (readMV mv) putMVar mv 'a' threadDelay (5 * 10^6) putMVar mv 'b' threadDelay (5 * 10^6) readMV mv = forever $ do ch <- modifyMVar mv modMV putChar ch >> hFlush stdout threadDelay (9*10^5) modMV 'a' = return ('c','a') modMV 'c' = return ('a','c') modMV x = return (x,x) ***/CODE*** Output is :- acacac The problem is that the output stops after 5 seconds and the program exits after 10 seconds. But why? Questions:- 1. Why does the output stop? (Shouldn't the reader thread continue even if the main thread blocks on the second putMVar?) 2. Why does it exit? (Shouldn't it be blocked at the second putMVar? The readMV thread now only modifies the MVar so it should never be empty) 3. Is there a race condition using modifyMVar while there is another thread blocked in a putMVar? (I am assuming the second putMVar succeeded, but where did the 'b' go?) Many thanks for any help Adrian.

At 4:08 PM +0000 1/15/10, Adrian Adshead wrote:
Hi everyone,
I have a beginer question on using MVar.
In the simple case I am getting what I expect...
***CODE*** module Main ( main ) where
import Control.Concurrent import System.IO
main = do mv <- newEmptyMVar putMVar mv 'a' threadDelay (5 * 10^6) putMVar mv 'b' threadDelay (5 * 10^6) ***/CODE***
Output after the first 5 second delay is :-
Demo.exe: thread blocked indefinitely
It even works as expected when there is a reading thread
***CODE*** module Main ( main ) where
import Control.Concurrent import Control.Monad import System.IO
main = do mv <- newEmptyMVar forkIO (readMV mv) putMVar mv 'a' threadDelay (5 * 10^6) putMVar mv 'b' threadDelay (5 * 10^6)
readMV mv = forever $ do ch <- takeMVar mv putChar ch >> hFlush stdout ***/CODE***
Output including expected delays :- ab
Then it starts to act unexpectedly
***CODE*** module Main ( main ) where
import Control.Concurrent import Control.Monad import System.IO
main = do mv <- newEmptyMVar forkIO (readMV mv) putMVar mv 'a' threadDelay (5 * 10^6) putMVar mv 'b' threadDelay (5 * 10^6)
readMV mv = forever $ do ch <- modifyMVar mv modMV putChar ch >> hFlush stdout threadDelay (9*10^5)
modMV 'a' = return ('c','a') modMV 'c' = return ('a','c') modMV x = return (x,x) ***/CODE***
Output is :- acacac
The problem is that the output stops after 5 seconds and the program exits after 10 seconds. But why?
Questions:-
1. Why does the output stop? (Shouldn't the reader thread continue even if the main thread blocks on the second putMVar?)
2. Why does it exit? (Shouldn't it be blocked at the second putMVar? The readMV thread now only modifies the MVar so it should never be empty)
3. Is there a race condition using modifyMVar while there is another thread blocked in a putMVar? (I am assuming the second putMVar succeeded, but where did the 'b' go?)
Many thanks for any help
Adrian.
I believe the explanation is that modifyMVar simply wraps takeMVar and putMVar around your modification action. It does not perform these two "atomically", contrary to what you seem to be expecting. Hence, the main thread is able to fill the MVar with 'b' in the short time the readMV thread leaves the MVar empty while doing its modifyMVar. This blocks the readMV thread (1.), allowing the main thread to proceed (2.) and ultimately exit. The 'b' went into the MVar, but the readMV thread never saw it, because it was waiting in vain to put back the 'a' it last withdrew. Dean
participants (2)
-
Adrian Adshead
-
Dean Herington