On Thu, May 28, 2009 at 14:41, Bertram Felgenhauer <bertram.felgenha...@googlemail.com> wrote: > Krzysztof Skrzętnicki wrote: >> 2009/5/27 Bertram Felgenhauer <bertram.felgenha...@googlemail.com>: >> > I wrote: >> >> Krzysztof Skrzętnicki wrote: >> >>> The code for modifying the counter: >> >>> (\ msg -> atomicModifyIORef ioref (\ cnt -> (cntMsg cnt msg,()))) >> >> >> >> atomicModifyIORef does not force the new value of the IORef. >> >> If the previous contents of the IORef is x, the new contents >> >> will be a thunk, >> >> >> >> (\ cnt -> (cntMsg cnt msg,())) x >> > >> > Sorry, it's slightly worse than that. The contents becomes >> > >> > sel_0 (\ cnt -> (cntMsg cnt msg, ())) x >> > >> > where sel_0 is basically an RTS internal version of fst. >> > >> > Instead of reading the new value of the IORef, you could also force the >> > old one: >> > >> > atomicModifyIORef ioref (\ cnt -> (cntMsg cnt msg, msg)) >>= (return $!) >> > >> >> Thanks for the tip, although it seems tricky to get it right. I wonder >> why there is no strict version of atomicModifyIORef? > > Something like this? > > -- | Stricter version of 'atomicModifyIORef', which prevents building > -- up huge thunks in the 'IORef' due to repeated modification. > -- Unlike 'atomicModifyIORef', 'atomicModifyIORef'' may block. > atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b > atomicModifyIORef' ioref f = do > res <- atomicModifyIORef ioref f > new <- readIORef ioref > new `seq` return res > > (The step that may block is forcing the new value - if another thread is > already evaluating part of the thunk, the currently executing thread > will block, waiting for the other thread to finish.) > >> Dually there might be a strict version of IORef datatype. > > One interesting feature of atomicModifyIORef is that its implementation > is lock-free, and never blocks (which affects exception handling): > replacing the old value by the new value is done with compare-and-swap > operation in a tight loop. Each iteration executes very quickly because > all it does is replace the reference to the old value in the new thunk. > > With a strict IORef, the time window between reading the old value and > storing the new value would become arbitrarily large, because you'd have > to force the new value before exchanging it with the old value. So a > reasonable implementation would have to use locks instead, I think, > making atomicModifyIORef more expensive, and less useful in contexts > that block exceptions.
We may as well drop the 'atomic' keyword and provide a warning about possible blocking of thread. The end user may forkIO the modification if he wants to. I modified the code as follows, it works now: (\ msg -> atomicModifyIORef ioref (\ cnt -> (cntMsg cnt msg,cnt)) >>= (return $!)) Thank you all for your help! Best regards Christopher Skrzętnicki _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe