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.
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.
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))".
Quantity that has been passed to a blocked waiter but not picked up is not counted. If the blocked waiter is killed before picking it up then the passed quantity will be recovered by the next waiter. In this exceptional case this next waiter may see an available total that is different than returned by peekAvail.
A version of peekAvail
that joins the FIFO queue of wait
and waitF
can be acheived by
"waitF m (x -> (0,x))" but this will block if x is negative. On the other hand this method
will see the total including any recovered quantity.