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

Safe Haskell | Safe-Inferred
Language | Haskell98

Control.Concurrent.MSampleVar

Contents

- Sample Variables

Description

`MSampleVar` is a safer version of the Control.Concurrent.SampleVar in base. The same problem as QSem(N) is being fixed, that of handling waiters that die before being woken normally. For Control.Concurrent.SampleVar in base this error can lead to thinking a full `SampleVar` is really empty and cause `writeSampleVar` to hang. The `MSampleVar` in this module is immune to this error, and has a simpler implementation.

Synopsis

- data MSampleVar a
- newEmptySV :: IO (MSampleVar a)
- newSV :: a -> IO (MSampleVar a)
- emptySV :: MSampleVar a -> IO ()
- readSV :: MSampleVar a -> IO a
- writeSV :: MSampleVar a -> a -> IO ()
- isEmptySV :: MSampleVar a -> IO Bool

# Sample Variables

data MSampleVar a Source #

Sample variables are slightly different from a normal `MVar`:

- Reading an empty `MSampleVar` causes the reader to block. (same as `takeMVar` on empty `MVar`)
- Reading a filled `MSampleVar` empties it and returns value. (same as `takeMVar`)
- Try reading a filled `MSampleVar` returns a Maybe value. (same as `tryTakeMVar`)
- Writing to an empty `MSampleVar` fills it with a value, and potentially, wakes up a blocked reader (same as for `putMVar` on empty `MVar`).
- Writing to a filled `MSampleVar` overwrites the current value. (different from `putMVar` on full `MVar`.)

The readers queue in FIFO order, with the lead reader joining the writers in a second FIFO queue to access the stored value. Thus writers can jump the queue of non-leading waiting readers to update the value, but the lead reader has to wait on all previous writes to finish before taking the value.

This design choice emphasises that each reader sees the most up-to-date value possible while still guaranteeing progress.

#### Instances

Instances details

Eq (MSampleVar a) Source # |
Instance details Defined in Control.Concurrent.MSampleVar Methods (==) :: MSampleVar a -> MSampleVar a -> Bool Source # (/=) :: MSampleVar a -> MSampleVar a -> Bool Source #

newEmptySV :: IO (MSampleVar a) Source #

`newEmptySV` allocates a new MSampleVar in an empty state. No futher allocation is done when using the `MSampleVar`.

newSV :: a -> IO (MSampleVar a) Source #

`newSV` allocates a new MSampleVar containing the passed value. The value is not evalated or forced, but stored lazily. No futher allocation is done when using the `MSampleVar`.

emptySV :: MSampleVar a -> IO () Source #

If the `MSampleVar` is full, forget the value and leave it empty. Otherwise, do nothing. This avoids any the FIFO queue of blocked `readSV` threads.

`emptySV` can block and be interrupted, in which case it does nothing. If `emptySV` returns then it left the `MSampleVar` in an empty state.

readSV :: MSampleVar a -> IO a Source #

Wait for a value to become available, then take it and return. The queue of blocked `readSV` threads is a fair FIFO queue.

`readSV` can block and be interrupted, in which case it takes nothing. If 'readSV returns normally then it has taken a value.

writeSV :: MSampleVar a -> a -> IO () Source #

Write a value into the `MSampleVar`, overwriting any previous value that was there.

`writeSV` can block and be interrupted, in which case it does nothing.

isEmptySV :: MSampleVar a -> IO Bool Source #

`isEmptySV` can block and be interrupted, in which case it does nothing. If `isEmptySV` returns then it reports the momentary status the `MSampleVar`. Using this value without producing unwanted race conditions is left up to the programmer.