Is this a bug in multithreading code?

Hi all, does someone know why this program works ------------------------ import Concurrent loopM = sequence_ . repeat main = do v <- newMVar 0 forkIO (loopM (modifyMVar_ v (return . (1+)))) -- forkIO (loopM (modifyMVar_ v (return . (1+)))) loopM (readMVar v >>= print) ------------------------- but uncommenting the commented line makes the program fail with "stack overflow" ? Thanks for help Vincenzo

On Wed, Apr 23, 2003 at 03:51:25PM +0200, Nick Name wrote:
Hi all, does someone know why this program works
------------------------ import Concurrent
loopM = sequence_ . repeat
main = do v <- newMVar 0 forkIO (loopM (modifyMVar_ v (return . (1+)))) -- forkIO (loopM (modifyMVar_ v (return . (1+)))) loopM (readMVar v >>= print) -------------------------
but uncommenting the commented line makes the program fail with "stack overflow" ?
Thanks for help
Vincenzo
It definitely seems a bug to me. Though I'm not sure if it's in your code or in Concurrent ;) However, the following code _does_ work, which makes me suspect it has something to do with the locking done inside of an MVar. import Control.Concurrent loopM = sequence_ . repeat main = do v <- newMVar 0 forkIO $ loopM $ do modifyMVar_ v $ return . (1+) forkIO $ loopM $ do modifyMVar_ v $ return . (1+) loopM $ do readMVar v >>= print --withMVar v print Swapping the last 2 lines (that is, their comments) makes it crash again. And I guess this actually _is_ the code you should use: withMVar is a "safe wrapper for operating on the contents of an MVar", which is exactly what you're doing. Does anyone else know what exactly is going on? Happy hacking, Remi -- Nobody can be exactly like me. Even I have trouble doing it.

Hi all, does someone know why this program works
------------------------ import Concurrent
loopM = sequence_ . repeat
main = do v <- newMVar 0 forkIO (loopM (modifyMVar_ v (return . (1+)))) -- forkIO (loopM (modifyMVar_ v (return . (1+)))) loopM (readMVar v >>= print) -------------------------
but uncommenting the commented line makes the program fail with "stack overflow" ?
There's four interesting pieces of code here: M1 = the code in main before the forks M2 = the body of the loop at the end of main A = the body of the loop in the first forked thread B = the body of the loop in the second forked thread One possible execution sequence is: M1 A B A B A B A B A B M2 ... With this, the code in A and B will build a bigger and bigger suspended computation of the form 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 and then when M2 runs it will evaluate this computation and update it. This evaluation requires stack space proportional to the number of As and Bs. A more likely execution sequence would have each thread run for a significant timeslice so you'd see perhaps 10000 A's then 10000 B's then 10000 M2s. M1 A A A A A A A A A ... A A A A A A B B B B B B B B B B B B B B B B B B ... B B B B B B B B M2 M2 M2 M2 M2 M2 M2 M2 M2 M2 That first M2 will perform the same evaluation as before (i.e., adding all those ones together) but, in this more likely scenario, will require a very, very large stack. I conjecture that the problem would go away if you added appropriate uses of seq or $! to your program so that the value stored in the MVar was always fully evaluated. I leave writing a function which does this as an exercise - though not a completely trivial one since both monads and higher order functions make blindly adding $! everywhere ineffective. -- Alastair Reid alastair@reid-consulting-uk.ltd.uk Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/
participants (3)
-
Alastair Reid
-
Nick Name
-
Remi Turk