SafeSemaphore-0.9.0: Much safer replacement for QSemN, QSem, and SampleVar

Portabilitynon-portable (concurrency)
Stabilityexperimental
Maintainerhaskell@list.mightyreason.com
Safe HaskellSafe-Infered

Control.Concurrent.MSemN2

Description

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.

Synopsis

Documentation

data MSemN i Source

A MSemN is a quantity semaphore, in which the available quantity may be signalled or waited for in arbitrary amounts.

Instances

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.

with :: Integral i => MSemN i -> i -> IO a -> IO aSource

with takes a quantity of the semaphore to take and hold while performing the provided operation. with ensures the quantity of the sempahore cannot be lost if there are exceptions. This uses bracket to ensure wait and signal get called correctly.

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.