[Haskell-cafe] TMVar's are great but fail under ghc 6.10.1 windows

Bertram Felgenhauer bertram.felgenhauer at googlemail.com
Tue Mar 31 21:20:47 EDT 2009


Alberto G. Corona  wrote:
> however, It happens that fails in my windows box with ghc 6.10.1  , single
> core
> 
> here is the code and the results:
> 
> -----------begin code:
> module Main where
> 
> import Control.Concurrent.STM
> 
> import Control.Concurrent
> import System.IO.Unsafe
> import GHC.Conc
> 
> 
> 
> mtxs=  unsafePerformIO $ mapM newTMVarIO $ take 5 $ repeat  0
> 
> proc i= atomically $ do
>  unsafeIOToSTM $ putStr $ "init of process "++ show i++"\n"

As Sterling points out, unsafeIOToSTM is really unsafe. A fundamental
restriction is that the IO action used with unsafeIOToSTM may not block.
However, putStr may block.

It's actually possible to do the logging without blocking:

>>> cut here >>>
module Main where

import Control.Concurrent
import Control.Concurrent.STM
import GHC.Conc
import Control.Concurrent.MVar
import Data.IORef
import Control.Monad

data Logger = Logger (IORef [String]) (MVar ())

newLogger :: IO Logger
newLogger = do
    ref  <- newIORef []
    wake <- newEmptyMVar
    return $ Logger ref wake

logLogger :: Logger -> String -> IO ()
logLogger (Logger ref wake) msg = do
    atomicModifyIORef ref $ \msgs -> (msg:msgs, ())
    tryPutMVar wake ()
    return ()

dumpLogger :: Logger -> IO ()
dumpLogger (Logger ref wake) = forever $ do
    takeMVar wake
    msgs <- atomicModifyIORef ref $ \msgs -> ([], msgs)
    putStr $ unlines . reverse $ msgs

proc log mtxs i = do
 let logSTM = unsafeIOToSTM . log
 xs' <- atomically $ do
   logSTM $ "init of process " ++ show i
   xs <- mapM takeTMVar mtxs
   mapM (\(mtx, x) -> putTMVar mtx (x+1)) $ zip mtxs xs
   xs' <- mapM readTMVar mtxs
   logSTM $ "End of processs " ++ show i ++ " result = " ++ show xs'
   return xs'
 log $ "Final result of process " ++ show i ++ " = " ++ show xs'

main = do
  log <- newLogger
  forkIO $ dumpLogger log
  mtxs <- replicateM 5 $ newTMVarIO 0
  mapM (forkIO . proc (logLogger log) mtxs) [1..5]
  threadDelay 1000000
<<<

And that gives reasonable results, for example:

init of process 1
End of processs 1 result= [1,1,1,1,1]
Final result of process 1 = [1,1,1,1,1]
init of process 2
End of processs 2 result= [2,2,2,2,2]
Final result of process 2 = [2,2,2,2,2]
init of process 3
init of process 4
End of processs 4 result= [3,3,3,3,3]
Final result of process 4 = [3,3,3,3,3]
init of process 5
End of processs 5 result= [4,4,4,4,4]
Final result of process 5 = [4,4,4,4,4]
End of processs 3 result= [3,3,3,3,3]
init of process 3
End of processs 3 result= [5,5,5,5,5]
Final result of process 3 = [5,5,5,5,5]

HTH,

Bertram


More information about the Haskell-Cafe mailing list