Is this a concurrency bug in base?

Jean-Marie Gaillourdet jmg at gaillourdet.net
Wed Oct 12 08:18:35 CEST 2011


Hi, 

I've continued my search for a proper workaround. Again, I did find some unexpected results. See below.

On 09.10.2011, at 17:56, wagnerdm at seas.upenn.edu wrote:

> Quoting Jean-Marie Gaillourdet <jmg at gaillourdet.net>:
> 
>> That sounds plausible. Do you see any workaround? Perhaps repeatedly evaluating typeOf?
> 
> If there's a concurrency bug, surely the workaround is to protect calls to the non-thread-safe function with a lock.
> 
>  typeOfWorkaround lock v = do
>      () <- takeMVar lock
>      x <- evaluate (typeOf v)
>      putMVar lock ()
>      return x
> 
> ~d

This is my previous program with your workaround, it is also attached as TypeRepEqLock.hs

import Control.Concurrent
import Control.Exception
import Control.Monad
import Data.Typeable
import System.IO.Unsafe

main :: IO ()
main =
do { fin1 <- newEmptyMVar
  ; fin2 <- newEmptyMVar

  ; forkIO $ typeOf' () >>= putMVar fin1 
  ; forkIO $ typeOf' () >>= putMVar fin2 

  ; t1 <- takeMVar fin1
  ; t2 <- takeMVar fin2
  ; if (t1 /= t2)
      then putStrLn $ "typeOf " ++ show t1 ++ " /= typeOf " ++ show t2
      else putStrLn "Ok"
  }


{-# NOINLINE lock #-}
lock :: MVar ()
lock = unsafePerformIO $ newMVar ()

-- Ugly workaround to http://hackage.haskell.org/trac/ghc/ticket/5540
typeOf' :: Typeable a => a -> IO TypeRep
typeOf' x =
do { () <- takeMVar lock
  ; t <- evaluate $ typeOf x
  ; putMVar lock ()
  ; return t
  }


Compile and execute:

$ ghc-7.0.3 -threaded -rtsopts TypeRepEqLock.hs
<snip>
$ while true ; do ./TypeRepEqLock +RTS -N ; done
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
Ok
TypeRepEqLock: thread blocked indefinitely in an MVar operation
Ok
Ok
Ok
^C^C

I'm sorry but I don't see how this program could ever deadlock, unless there is some more locking in typeOf and (==) on TypeReps. 

On the other side, my admittedly ugly workaround works fine for hours and hours.

import Control.Concurrent
import Control.Exception
import Control.Monad
import Data.Typeable

main :: IO ()
main =
do { fin1 <- newEmptyMVar
  ; fin2 <- newEmptyMVar

  ; forkIO $ return (typeOf' ()) >>= evaluate >>= putMVar fin1 
  ; forkIO $ return (typeOf' ()) >>= evaluate >>= putMVar fin2 

  ; t1 <- takeMVar fin1
  ; t2 <- takeMVar fin2
  ; if (t1 /= t2)
      then putStrLn $ "typeOf " ++ show t1 ++ " /= typeOf " ++ show t2
      else putStrLn "Ok"
  }

typeOf' val
  | t1 == t2 = t1
  | otherwise = typeOf' val
where
  t1 = typeOf'' val
  t2 = typeOf''' val
{-# NOINLINE typeOf' #-}


typeOf'' x = typeOf x
{-# NOINLINE typeOf'' #-}
typeOf''' x = typeOf x
{-# NOINLINE typeOf''' #-}


$ ghc-7.0.3 -threaded -rtsopts TypeRepEq.hs
<snip>
$ while true ; do ./TypeRepEq +RTS -N ; done
Ok
Ok
Ok
Ok
Ok
Ok
…

Any hints how to avoid the "thread blocked indefinitely in an MVar operation" exception?

Cheers,
Jean


-------------- next part --------------
A non-text attachment was scrubbed...
Name: TypeRepEqLock.hs
Type: application/octet-stream
Size: 765 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20111012/9d8d3271/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: TypeRepEq.hs
Type: application/octet-stream
Size: 730 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/glasgow-haskell-users/attachments/20111012/9d8d3271/attachment-0001.obj>


More information about the Glasgow-haskell-users mailing list