Atomically modifies the contents of an
IORef.
This function is useful for using
IORef in a safe way in a
multithreaded program. If you only have one
IORef, then using
atomicModifyIORef to access and modify it will prevent race
conditions.
Extending the atomicity to multiple
IORefs is problematic, so
it is recommended that if you need to do anything more complicated
then using
MVar instead is a good idea.
Conceptually,
atomicModifyIORef ref f = do
-- Begin atomic block
old <- readIORef ref
let r = f old
new = fst r
writeIORef ref new
-- End atomic block
case r of
(_new, res) -> pure res
The actions in the section labeled "atomic block" are not subject to
interference from other threads. In particular, it is impossible for
the value in the
IORef to change between the
readIORef
and
writeIORef invocations.
The user-supplied function is applied to the value stored in the
IORef, yielding a new value to store in the
IORef and a
value to return. After the new value is (lazily) stored in the
IORef,
atomicModifyIORef forces the result pair, but
does not force either component of the result. To force
both
components, use
atomicModifyIORef'.
Note that
atomicModifyIORef ref (_ -> undefined)
will raise an exception in the calling thread, but will
also
install the bottoming value in the
IORef, where it may be read
by other threads.
This function imposes a memory barrier, preventing reordering around
the "atomic block"; see
Data.IORef#memmodel for details.