base-4.6.0.1: Basic libraries

Portability | portable
Stability | experimental
Maintainer | libraries@haskell.org
Safe Haskell | Trustworthy

Data.IORef

Contents

- IORefs
  - Memory Model

Description

Mutable references in the IO monad.

Synopsis

- data IORef a
- newIORef :: a -> IO (IORef a)
- readIORef :: IORef a -> IO a
- writeIORef :: IORef a -> a -> IO ()
- modifyIORef :: IORef a -> (a -> a) -> IO ()
- modifyIORef' :: IORef a -> (a -> a) -> IO ()
- atomicModifyIORef :: IORef a -> (a -> (a, b)) -> IO b
- atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b
- atomicWriteIORef :: IORef a -> a -> IO ()
- mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a))

# IORefs

data IORef a

A mutable variable in the `IO` monad

Instances

Typeable1 IORef |
Eq (IORef a) |

newIORef :: a -> IO (IORef a)

Build a new `IORef`

readIORef :: IORef a -> IO a

Read the value of an `IORef`

writeIORef :: IORef a -> a -> IO ()

Write a new value into an `IORef`

modifyIORef :: IORef a -> (a -> a) -> IO ()

Mutate the contents of an `IORef`.

Be warned that `modifyIORef` does not apply the function strictly. This means if the program calls `modifyIORef` many times, but seldomly uses the value, thunks will pile up in memory resulting in a space leak. This is a common mistake made when using an IORef as a counter. For example, the following will likely produce a stack overflow:

    ref <- newIORef 0
    replicateM_ 1000000 $ modifyIORef ref (+1)
    readIORef ref >>= print

To avoid this problem, use `modifyIORef'` instead.

modifyIORef' :: IORef a -> (a -> a) -> IO ()

Strict version of `modifyIORef`

atomicModifyIORef :: IORef a -> (a -> (a, b)) -> IO b

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 `IORef`s is problematic, so it is recommended that if you need to do anything more complicated then using `MVar` instead is a good idea.

`atomicModifyIORef` does not apply the function strictly. This is important to know even if all you are doing is replacing the value. For example, this will leak memory:

    ref <- newIORef '1'
    forever $ atomicModifyIORef ref (\_ -> ('2', ()))

Use `atomicModifyIORef'` or `atomicWriteIORef` to avoid this problem.

atomicModifyIORef' :: IORef a -> (a -> (a, b)) -> IO b

Strict version of `atomicModifyIORef`. This forces both the value stored in the `IORef` as well as the value returned.

atomicWriteIORef :: IORef a -> a -> IO ()

Variant of `writeIORef` with the "barrier to reordering" property that `atomicModifyIORef` has.

mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a))

Make a `Weak` pointer to an `IORef`, using the second argument as a finalizer to run when `IORef` is garbage-collected

## Memory Model

In a concurrent program, `IORef` operations may appear out-of-order to another thread, depending on the memory model of the underlying processor architecture. For example, on x86, loads can move ahead of stores, so in the following example:

      maybePrint :: IORef Bool -> IORef Bool -> IO ()
      maybePrint myRef yourRef = do
        writeIORef myRef True
        yourVal <- readIORef yourRef
        unless yourVal $ putStrLn "critical section"

      main :: IO ()
      main = do
        r1 <- newIORef False
        r2 <- newIORef False
        forkIO $ maybePrint r1 r2
        forkIO $ maybePrint r2 r1
        threadDelay 1000000

it is possible that the string `critical section` is printed twice, even though there is no interleaving of the operations of the two threads that allows that outcome. The memory model of x86 allows `readIORef` to happen before the earlier `writeIORef`.

The implementation is required to ensure that reordering of memory operations cannot cause type-correct code to go wrong. In particular, when inspecting the value read from an `IORef`, the memory writes that created that value must have occurred from the point of view of the current therad.

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