If I share an IORef
among multiple threads, and use atomicModifyIORef
to write to it:
atomicModifyIORef ref (\_ -> (new, ()))
Is it safe to read the value with plain old readIORef
? Or is there a chance readIORef
will return the old value in another thread after atomicModifyIORef
has modified it?
I think that's what the documentation implies:
atomicModifyIORef acts as a barrier to reordering. Multiple atomicModifyIORef operations occur in strict program order. An atomicModifyIORef is never observed to take place ahead of any earlier (in program order) IORef operations, or after any later IORef operations.
I just want to be sure.
atomicModifyIORef
guarantees that nothing happens between the atomic read and the following atomic write, thus making the whole operation atomic. The comment that you quoted just states that no atomicModifyIORef
s will ever happen in parallel, and that the optimizer won't try to reorder the statements to optimize the program (separate reads and writes can safely be moved around in some cases; for example in a' <- read a; b' <- read b; write c $ a' + b'
, the reads can safely be reordered)
readIORef
is already atomic, since it only performs one operation.
However, you are discussing a different issue. Yes, if the atomicModify
happens at t=3ms
and the read
happens at t=4ms
, you will get the modified value. However; threads aren't guaranteed to run in parallel, so if you do (pseudocode):
forkIO $ do
sleep 100 ms
atomicModify
sleep 1000 ms
read
... there's no guarantee that the read will happen after the modify (it's extremely unlikely on modern OS's, though), because the operating system might decide to schedule the new short-lived thread in such a way that it doesn't happen in parallel.