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

Copyright | (c) Chris Kuklewicz 2011
License | 3 clause BSD-style (see the file LICENSE)
Maintainer | haskell@list.mightyreason.com
Stability | experimental
Portability | non-portable (concurrency)
Safe Haskell | Safe
Language | Haskell98

Control.Concurrent.MSem

Description

This is a literate haskell version of Control.Concurrent.MSem for increased clarity.

A semaphore in which operations may `wait` for or `signal` single units of value. This modules is intended to improve on Control.Concurrent.QSem.

This semaphore gracefully handles threads which die while blocked waiting. The fairness guarantee is that blocked threads are servied in a FIFO order.

If `with` is used to guard a critical section then no quantity of the semaphore will be lost if the activity throws an exception or if this thread is killed by the rest of the program.

`new` can initialize the semaphore to negative, zero, or positive quantity. `wait` always leaves the `MSem` with non-negative quantity. `signal` alawys adds one to the quantity.

The functions below are generic in (Integral i) with specialization to Int, Word, 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 `signal` is undefined. Using (MSem Integer) prevents the possibility of an overflow error. [ A version of `signal` that checks the upper bound could be added, but how would it report failure and how would you use this sanely? ]

Synopsis

- data MSem i
- new :: Integral i => i -> IO (MSem i)
- with :: Integral i => MSem i -> IO a -> IO a
- wait :: Integral i => MSem i -> IO ()
- signal :: Integral i => MSem i -> IO ()
- peekAvail :: Integral i => MSem i -> IO i

# Documentation

data MSem i

A `MSem` is a semaphore in which the available quantity can be added and removed in single units, and which can start with positive, zero, or negative value.

Instances

Eq (MSem i) |

new :: Integral i => i -> IO (MSem i)

`new` allows positive, zero, and negative initial values. The initial value is forced here to better localize errors.

The only way to achieve a negative value with MSem is to start negative with `new`. Once a negative quantity becomes non-negative by use of `signal` it will never later be negative.

with :: Integral i => MSem i -> IO a -> IO a

`with` takes a unit of value from the semaphore to hold while performing the provided operation. `with` ensures the quantity of the sempahore cannot be lost if there are exceptions or if killThread is used.

`with` uses `bracket_` to ensure `wait` and `signal` get called correctly.

wait :: Integral i => MSem i -> IO ()

`wait` will take one unit of value from the sempahore, but will block if the quantity available is not positive.

If `wait` returns normally (not interrupted) then it left the `MSem` 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 (the FIFO guarantee).

signal :: Integral i => MSem i -> IO ()

`signal` adds one unit to the sempahore. Overflow is not checked.

`signal` may block, but it cannot be interrupted, which allows it to dependably restore value to the `MSem`. All `signal`, `peekAvail`, and the head waiter may momentarily block in a fair FIFO manner.

peekAvail :: Integral i => MSem i -> IO i

`peekAvail` skips the queue of any blocked `wait` threads, but may momentarily block on `signal`, 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.

Note that Control.Concurrent.MSemN offers a more powerful API for making decisions based on the available amount.