Copyright | (c) 2016--2018 Michael Walker |
---|---|
License | MIT |
Maintainer | Michael Walker <mike@barrucadu.co.uk> |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
Deprecated: Import Control.Concurrent.Classy.IORef instead
Deprecated re-exports of IORef
functions under the old CRef
names.
Synopsis
- type CRef m a = IORef m a
- newCRef :: MonadConc m => a -> m (CRef m a)
- newCRefN :: MonadConc m => String -> a -> m (CRef m a)
- readCRef :: MonadConc m => CRef m a -> m a
- writeCRef :: MonadConc m => CRef m a -> a -> m ()
- modifyCRef :: MonadConc m => CRef m a -> (a -> a) -> m ()
- modifyCRef' :: MonadConc m => CRef m a -> (a -> a) -> m ()
- atomicModifyCRef :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- atomicModifyCRef' :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- atomicWriteCRef :: MonadConc m => CRef m a -> a -> m ()
- casCRef :: MonadConc m => CRef m a -> Ticket m a -> a -> m (Bool, Ticket m a)
- modifyCRefCAS :: MonadConc m => CRef m a -> (a -> (a, b)) -> m b
- modifyCRefCAS_ :: MonadConc m => CRef m a -> (a -> a) -> m ()
CRefs
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.
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 CRef
s 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.