
Eugene Kirpichov
daemon :: IO () -> IO (IO ()) daemon action = do stopvar <- newIORef False let run = do stop <- readIORef stopvar if stop then return () else (action >> run) forkIO run return (writeIORef stopvar True)
In this case, it's simply a coincidence that it's safe. It's because you're using an IORef Bool, and because writes to a Bool variable are atomic on virtually all platforms. An Integer may already fail to be thread-safe. You need more care and the payoff is zero. If you still insist on using IORefs, at least use the atomic function above, but that destroys the little performance benefit of using IORefs, unless GHC does some intelligent optimization here, which I doubt.
This would be the case if the IORef was unboxed, but it is boxed, so writing an IORef is actually writing a pointer to a thunk; here, Bool and Integer have no difference at all. However, I don't know whether GHC makes pointer writes atomic on all platforms (Java does, so it's at least doable).
It will likely work, but the compiler is not required to make pointer writes atomic, and it would be an enormous performance hit. The pointer write is more likely atomic by platform, not by the code, but even there I would be very careful, because it may be not the case for SMP systems. And you know what happens, when a pointer race condition occurs. The selection between MVar and IORef is essentially a "security or performance" question. Especially for daemons I would rather choose security. MVar gives you that security with _the same amount of code_. And to prove that IORefs do lead to a pointer race condition and hence are insecure, try the following code: main :: IO () main = do ref <- newIORef False forkIO $ forever $ modifyIORef ref not forever $ readIORef ref >>= print It crashes for me. I'm using GHC 6.10.1 on an Athlon 64 X2 (32 bits system). The error message reads: test: internal error: schedule: invalid what_next field (GHC version 6.10.1 for i386_unknown_linux) Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug Greets, Ertugrul. -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://blog.ertes.de/