Is this a concurrency bug in base?

Daniel Fischer daniel.is.fischer at googlemail.com
Sun Oct 9 17:27:20 CEST 2011


Jean-Marie Gaillourdet:
> the Eq instance of TypeRep shows the same non-deterministic behavior:

Of course, equality on TypeReps is implemented by comparison of the Keys.

On Sunday 09 October 2011, 16:40:13, Jean-Marie Gaillourdet wrote:
> Hi Daniel,

> I've been chasing the source of the non-deterministic of my library for
> quite some time now. And at several points in time I had the impression
> that modifyMVar would not always be atomic.

It isn't:

"MVars offer more flexibility than IORefs, but less flexibility than STM. 
They are appropriate for building synchronization primitives and performing 
simple interthread communication; however they are very simple and 
susceptible to race conditions, deadlocks or uncaught exceptions. Do not 
use them if you need perform larger atomic operations such as reading from 
multiple variables: use STM instead.

In particular, the bigger functions in this module (readMVar, swapMVar, 
withMVar, modifyMVar_ and modifyMVar) are simply the composition of a 
takeMVar followed by a putMVar with exception safety. These only have 
atomicity guarantees if all other threads perform a takeMVar before a 
putMVar as well; otherwise, they may block."

But I don't think that's the problem here.

> (Of course under the
> assumption that no other code touches the MVar). But in that case as
> well as in the case here it is only reproducible by looping the
> execution of the binary. Moving the loop into the Haskell program will
> show the bug in the first iteration or never.

That's what I expect.
I think what happens is:

-- from Data.Typeable

cache = unsafePerformIO $ ...


mkTyConKey :: String -> Key
mkTyConKey str 
  = unsafePerformIO $ do
        let Cache {next_key = kloc, tc_tbl = tbl} = cache
        mb_k <- HT.lookup tbl str
        case mb_k of
          Just k  -> return k
          Nothing -> do { k <- newKey kloc ;
                          HT.insert tbl str k ;
                          return k }

occasionally, the second thread gets to perform the lookup before the first 
has updated the cache, so both threads create a new entry and update the 
cache.

If you loop in the Haskell programme, after the first round each thread 
definitely finds an entry for "()", so the cache isn't updated anymore.

> 
> I will report a bug.
> 
> Jean




More information about the Glasgow-haskell-users mailing list