concurrency-1.11.0.0: Typeclasses, functions, and data types for concurrency and STM.

Copyright(c) 2016--2018 Michael Walker
LicenseMIT
MaintainerMichael Walker <mike@barrucadu.co.uk>
Stabilityexperimental
Portabilityportable
Safe HaskellNone
LanguageHaskell2010

Control.Concurrent.Classy.CRef

Contents

Description

Deprecated: Import Control.Concurrent.Classy.IORef instead

Deprecated re-exports of IORef functions under the old CRef names.

Synopsis

CRefs

type CRef m a = IORef m a Source #

Type alias for IORef.

newCRef :: MonadConc m => a -> m (CRef m a) Source #

Create a new reference.

newCRefN :: MonadConc m => String -> a -> m (CRef m a) Source #

Create a new reference, but it is given a name which may be used to present more useful debugging information.

readCRef :: MonadConc m => CRef m a -> m a Source #

Read the current value stored in a reference.

writeCRef :: MonadConc m => CRef m a -> a -> m () Source #

Write a new value into an CRef, without imposing a memory barrier. This means that relaxed memory effects can be observed.

modifyCRef :: MonadConc m => CRef m a -> (a -> a) -> m () Source #

Mutate the contents of a CRef.

Be warned that modifyCRef does not apply the function strictly. This means if the program calls modifyCRef many times, but seldomly uses the value, thunks will pile up in memory resulting in a space leak.

modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m () Source #

Strict version of modifyCRef

atomicModifyCRef :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b Source #

Atomically modify the value stored in a reference. This imposes a full memory barrier.

atomicModifyCRef' :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b Source #

Strict version of atomicModifyCRef. This forces both the value stored in the CRef as well as the value returned.

atomicWriteCRef :: MonadConc m => CRef m a -> a -> m () Source #

Replace the value stored in a reference, with the barrier-to-reordering property that atomicModifyIORef has.

Compare-and-swap

casCRef :: MonadConc m => CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a) Source #

Perform a machine-level compare-and-swap (CAS) operation on a CRef. Returns an indication of success and a Ticket for the most current value in the CRef. This is strict in the "new" value argument.

modifyCRefCAS :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b Source #

A replacement for atomicModifyCRef using a compare-and-swap.

This is strict in the "new" value argument.

modifyCRefCAS_ :: MonadConc m => CRef m a -> (a -> a) -> m () Source #

A variant of modifyCRefCAS which doesn't return a result.

Memory Model

In a concurrent program, CRef operations may appear out-of-order to another thread, depending on the memory model of the underlying processor architecture. For example, on x86 (which uses total store order), loads can move ahead of stores. Consider this example:

crefs :: MonadConc m => m (Bool, Bool)
crefs = do
  r1 <- newCRef False
  r2 <- newCRef False

  x <- spawn $ writeCRef r1 True >> readCRef r2
  y <- spawn $ writeCRef r2 True >> readCRef r1

  (,) <$> readMVar x <*> readMVar y

Under a sequentially consistent memory model the possible results are (True, True), (True, False), and (False, True). Under total or partial store order, (False, False) is also a possible result, even though there is no interleaving of the threads which can lead to this.

We can see this by testing with different memory models:

> autocheckWay defaultWay SequentialConsistency relaxed
[pass] Never Deadlocks
[pass] No Exceptions
[fail] Consistent Result
       (False,True) S0---------S1----S0--S2----S0--

       (True,True) S0---------S1-P2----S1---S0---

       (True,False) S0---------S2----S1----S0---
False
> autocheckWay defaultWay TotalStoreOrder  relaxed
[pass] Never Deadlocks
[pass] No Exceptions
[fail] Consistent Result
        (False,True) S0---------S1----S0--S2----S0--

        (False,False) S0---------S1--P2----S1--S0---

        (True,False) S0---------S2----S1----S0---

        (True,True) S0---------S1-C-S2----S1---S0---
False

Traces for non-sequentially-consistent memory models show where writes to CRefs are committed, which makes a write visible to all threads rather than just the one which performed the write. Only writeCRef is broken up into separate write and commit steps, atomicModifyCRef is still atomic and imposes a memory barrier.