AVars are a form of transactional variables. They internally use a tail
recursive function to carry the state
of the variable, and allow for
use in concurrent systems, where actions are guaranteed to happen. They
are designed to cope with exceptions thrown by any modifying functions;
any exception thrown during a transaction will either be passed back to
the caller or ignored, and the variable keeps on running.
They are handy for applications like keeping track of resources by incrementing and decrementing the variable. They should not be used in a way which you would read the variable, then modify it based on the result recieved, but rather using the provided functions. If this was not done, the variable's value is very likely to have changed in the mean time.
- data AVar a
- data Transaction a
- putAVar :: AVar a -> a -> IO ()
- newAVar :: a -> IO (AVar a)
- putMVar :: MVar a -> a -> IO ()
- modAVar :: AVar a -> (a -> a) -> IO (Maybe SomeException)
- modAVar' :: AVar a -> (a -> (a, b)) -> IO (Either SomeException b)
- justModAVar :: AVar a -> (a -> a) -> IO ()
- getAVar :: AVar a -> IO a
- condModAVar :: AVar a -> (a -> Bool) -> (a -> a) -> (a -> a) -> IO (Either SomeException Bool)
- swapAVar :: AVar a -> a -> IO (Either SomeException a)
Types
AVar
s are the means through communication with the variable are conducted.
They contain a Chan that is connected
to the variable, and is read by the
variable's handler
function.
data Transaction a Source
A Transaction
describes what should happen to a variable.
They are only used internally, and are here just for reference.
Put a | puts the a into the variable |
Get (MVar a) | reads the variable |
Mod (a -> a) (MVar (Maybe SomeException)) | modifies the variable |
JustMod (a -> a) | Just modifies the variable (unless an exception occurs) |
forall b . Mod' (a -> (a, b)) (MVar (Either SomeException b)) | modifies the variable, returning the b result to the caller |
Atom (a -> Bool) (a -> a) (a -> a) (MVar (Either SomeException Bool)) | conditionally modifies a variable |
functions on AVars
putAVar :: AVar a -> a -> IO ()Source
putAVar
replaces the currect value in the variable with the given x
newAVar :: a -> IO (AVar a)Source
newAVar
creates a new variable. It forks off the handler
that does the
work for the variable itself and creates a new AVar.
putMVar :: MVar a -> a -> IO ()
Put a value into an MVar
. If the MVar
is currently full,
putMVar
will wait until it becomes empty.
There are two further important properties of putMVar
:
-
putMVar
is single-wakeup. That is, if there are multiple threads blocked inputMVar
, and theMVar
becomes empty, only one thread will be woken up. The runtime guarantees that the woken thread completes itsputMVar
operation. - When multiple threads are blocked on an
MVar
, they are woken up in FIFO order. This is useful for providing fairness properties of abstractions built usingMVar
s.
modAVar :: AVar a -> (a -> a) -> IO (Maybe SomeException)Source
modAVar
takes a function from a to a, and returns Nothing if nothing went
wrong, or Just e, where e is an exception thrown by the function.
modAVar' :: AVar a -> (a -> (a, b)) -> IO (Either SomeException b)Source
modAVar'
is like modAVar, but it modifies the variable, along with
returning a result of type b, within an Either e b.
justModAVar :: AVar a -> (a -> a) -> IO ()Source
justModAVar
will attempt to run the given function on the variable.
It does not report back on its sucess or failure, and if the function
produces an exception, the variable is left unchanged. It should be
used when you just want to modify the variable, and keep running,
without waiting for the action to complete.
condModAVar :: AVar a -> (a -> Bool) -> (a -> a) -> (a -> a) -> IO (Either SomeException Bool)Source
condModAVar
applies the first finction to the current value in the
AVar, and if true will modify the value using the second function if
it results in True, or the third function if it results in Fasle.