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

StackOverflow https://stackoverflow.com/questions/9328828

  •  30-04-2021
  •  | 
  •  

Domanda

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.

È stato utile?

Soluzione

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.

Altri suggerimenti

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.

You don't want to use IORef with multiple threads, since they give basically no guarantees. I usually use an MVar instead.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top