Portability | non-portable (concurrency) |
---|---|
Stability | experimental |
Maintainer | haskell@list.mightyreason.com |
Safe Haskell | Safe-Inferred |
Quantity semaphores in which each thread may wait for an arbitrary amount. This modules is intended to improve on Control.Concurrent.QSemN.
This semaphore gracefully handles threads which die while blocked waiting for quantity. The fairness guarantee is that blocked threads are FIFO. An early thread waiting for a large quantity will prevent a later thread waiting for a small quantity from jumping the queue.
If with
is used to guard a critical section then no quantity of the semaphore will be lost
if the activity throws an exception.
The functions below are generic in (Integral i) with specialization to Int and Integer.
Overflow warning: These operations do not check for overflow errors. If the Integral type is too small to accept the new total then the behavior of these operations is undefined. Using (MSem Integer) prevents the possibility of an overflow error.
- data MSemN i
- new :: Integral i => i -> IO (MSemN i)
- with :: Integral i => MSemN i -> i -> IO a -> IO a
- wait :: Integral i => MSemN i -> i -> IO ()
- signal :: Integral i => MSemN i -> i -> IO ()
- withF :: Integral i => MSemN i -> (i -> (i, b)) -> ((i, b) -> IO a) -> IO a
- waitF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)
- signalF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)
- peekAvail :: Integral i => MSemN i -> IO i
Documentation
A MSemN
is a quantity semaphore, in which the available quantity may be signalled or
waited for in arbitrary amounts.
new :: Integral i => i -> IO (MSemN i)Source
new
allows positive, zero, and negative initial values. The initial value is forced here to
better localize errors.
wait :: Integral i => MSemN i -> i -> IO ()Source
wait
allow positive, zero, and negative wanted values. Waiters may block, and will be handled
fairly in FIFO order. Waiters will succeed when the wanted value is less than or equal to the
available value. The FIFO order means that a wait
for a large quantity that blocks will prevent later
requests from being considered even if the later requests would be for a small quantity that could be fulfilled.
If wait
returns without interruption then it left the MSemN
with a remaining quantity that was
greater than or equal to zero. If wait
is interrupted then no quantity is lost. If wait
returns without interruption then it is known that each earlier waiter has definitely either been
interrupted or has retured without interruption.
signal :: Integral i => MSemN i -> i -> IO ()Source
signal
allows positive, zero, and negative values, thus this is also way to remove quantity
that skips any threads in the 'wait'/'waitF' queue. If the new total is greater than the next
value being waited for (if present) then the first waiter is woken. If there are queued waiters
then the next one will wake after a waiter has proceeded and notice the remaining value; thus a
single signal
may result in several waiters obtaining values. Waking waiting threads is
asynchronous.
signal
may block, but it cannot be interrupted, which allows it to dependably restore value to
the MSemN
. All signal
, signalF
, peekAvail
, and the head waiter may momentarily block in a
fair FIFO manner.
withF :: Integral i => MSemN i -> (i -> (i, b)) -> ((i, b) -> IO a) -> IO aSource
withF
takes a pure function and an operation. The pure function converts the available
quantity to a pair of the wanted quantity and a returned value. The operation takes the result
of the pure function. withF
ensures the quantity of the sempahore cannot be lost if there
are exceptions. This uses bracket
to ensure waitF
and signal
get called correctly.
Note: A long running pure function will block all other access to the MSemN
while it is
evaluated.
waitF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)Source
waitWith
takes the MSemN
and a pure function that takes the available quantity and computes the
amount wanted and a second value. The value wanted is stricly evaluated but the second value is
returned lazily.
waitF
allow positive, zero, and negative wanted values. Waiters may block, and will be handled
fairly in FIFO order. Waiters will succeed when the wanted value is less than or equal to the
available value. The FIFO order means that a waitF
for a large quantity that blocks will prevent later
requests from being considered even if the later requests would be for a small quantity that could be fulfilled.
If waitF
returns without interruption then it left the MSemN
with a remaining quantity that was
greater than or equal to zero. If waitF
or the provided function are interrupted then no
quantity is lost. If waitF
returns without interruption then it is known that each previous
waiter has each definitely either been interrupted or has retured without interruption.
Note: A long running pure function will block all other access to the MSemN
while it is
evaluated.
signalF :: Integral i => MSemN i -> (i -> (i, b)) -> IO (i, b)Source
Instead of providing a fixed change to the available quantity, signalF
applies a provided
pure function to the available quantity to compute the change and a second value. The
requested change is stricly evaluated but the second value is returned lazily. If the new total is
greater than the next value being waited for then the first waiter is woken. If there are queued
waiters then the next one will wake after a waiter has proceeded and notice the remaining value;
thus a single signalF
may result in several waiters obtaining values. Waking waiting threads
is asynchronous.
signalF
may block, and it can be safely interrupted. If the provided function throws an error
or is interrupted then it leaves the MSemN
unchanged. All signal
, signalF
, peekAvail
, and
the head waiter may momentarily block in a fair FIFO manner.
Note: A long running pure function will block all other access to the MSemN
while it is
evaluated.
peekAvail :: Integral i => MSemN i -> IO iSource
peekAvail
skips the queue of any blocked wait
and waitF
threads, but may momentarily
block on signal
, signalF
, other peekAvail
, and the head waiter. This returns the amount of
value available to be taken. Using this value without producing unwanted race conditions is left
up to the programmer.
peekAvail
is an optimized form of "signalF m (x -> (0,x))".
A version of peekAvail
that joins the FIFO queue of wait
and waitF
can be acheived by
"waitF m (x -> (0,x))"