Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When sharing an IORef, is it safe to read with readIORef as long as I'm writing with atomicModifyIORef?

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.

like image 611
Joey Adams Avatar asked Feb 17 '12 12:02

Joey Adams


2 Answers

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 atomicModifyIORefs 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.

like image 103
dflemstr Avatar answered Sep 20 '22 00:09

dflemstr


If you want to share a mutable reference between several threads, you really should use TVar instead IORef. That's the whole motivation for TVars after all. You use TVars pretty much the same way as IORefs, but any access or modification needs to be enclosed inside an atomically block which always guarateed to be an atomic operation.

like image 32
shang Avatar answered Sep 22 '22 00:09

shang