Haskell: How does 'atomicModifyIORef' work?

atomic, compare-and-swap, concurrency, haskell, locking

Solution

`atomicModifyIORef` takes a `r :: IORef a` and a function `f :: a -> (a, b)` and does the following:

It reads the value of `r` and applies `f` to this value, yielding `(a',b)`. Then the `r` is updated with the new value `a'` while `b` is the return value. This read and write access is done atomically.

Of course this atomicity only works if all accesses to `r` are done via `atomicModifyIORef`. Note that you can find this information by looking at the source [1].

[1] https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-IORef.html#v:atomicModifyIORef

Problem

Can someone explain how `atomicModifyIORef` works? In particular: (1) Does it wait for a lock, or optimistically try and retry if there's contention (like `TVar`). (2) Why is the signature of `atomicModifyIORef` different to the signature of `modifyIORef`? In particular, what is this extra variable `b`? Edit: I think I've figured out the answer to (2), in that `b` is a value to be extracted (this can be empty if not needed). In a single threaded program, knowing the value is trivial, but in a multithreaded program, one may want to know what the previous value was at the time of the function being applied. I assume this is why `modifyIORef` doesn't have this extra return value (as such usages of `modifyIORef` with this return value probably should use `atomicModifyIORef` anyway. I'm still interested in the answer to (1) though.

Original source