The Revenge of Finalizers

George Russell ger at tzi.de
Thu Oct 17 10:51:04 EDT 2002


Simon Marlow wrote:
[snip]
> 
> Ok, so it relies crucially on the fact that the 'if' causes evaluation.
> (you might have written it to be more lazy, so that the pair was
> returned immediately without evaluating contents1 first, for example).
> 
> In that case, yes I agree it is horrible :)
[snip]
Flattery like that will get you nowhere.  However in general I think
we can hide some of the horribleness from the user:

modify2IORefs :: IORef a -> IORef b -> (a -> b -> (a,b,c)) -> IO c
modify2IORefs ioRefA ioRefB updateFn =
   do
      res <- atomicModifyIORef ioRefA (\ a0 ->
         unsafePerformIO (do
            atomicModifyIORef ioRefB (\ b0 ->
               let
                  (a1,b1,c) = updateFn a0 b0
               in
                  a0 `seq` b0 `seq` (b1,(a1,c))
               )
            )
         )
      
      block (res `seq` return res)

Modulo whatever stupid type errors I have made, I think this should
provide a safe atomic update of two IORefs, except that you can
get non-termination should you set up circular dependencies.
However the latter problem (except that you will get deadlock) can occur
if you try to write
   modify2MVars :: MVar a -> MVar b -> (a -> b -> (a,b,c)) -> IO c
and are I fear unsolvable, without a global lock.

I am not sure if all those seqs are necessary, but as Simon PJ would
say, my brain is hurting.



More information about the FFI mailing list