f package:SafeSemaphore

Provides a fair RWLock, similar to one from Java, which is itself documented at http://download.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html There are complicated policy choices that have to be made. The policy choices here are different from the ones for the RWLock in concurrent-extras. The FairRWLock may be in a free unlocked state, it may be in a read locked state, or it may be a write locked state. Many running threads may hold the read lock and execute concurrently. Only one running thread may hold the write lock. The scheduling is a fair FIFO queue that avoids starvation. When in the read lock state the first acquireWrite will block, and subsequent acquireRead and acquireWrite will queue in order. When in the write locked state all other threads trying to acquireWrite or acquireRead will queue in order. FairRWLock allows recursive write locks, and it allows recursive read locks, and it allows the write lock holding thread to acquire read locks. When the current writer also holds read locks and then releases its last write lock it will immediately convert to the read locked state (and other waiting readers may join it). When a reader acquires a write lock it will (1) release all its read locks, (2) wait to acquire the write lock, (3) retake the same number of read locks released in (1). The preferred way to use this API is sticking to new, withRead, and withWrite. No sequence of calling acquire on a single RWLock should lead to deadlock. Exceptions, espcially from killThread, do not break withRead or withWrite. The withRead and withWrite ensure all locks get released when exiting due to an exception. The readers and writers are always identified by their ThreadId. Each thread that calls acquireRead must later call releaseRead from the same thread. Each thread that calls acquireWrite must later call releaseWrite from the same thread. The main way to misuse a FairRWLock is to call a release without having called an acquire. This is reported in the (Left error) outcomes from releaseRead and releaseWrite. Only if the FairRWLock has a bug and finds itself in an impossible state then it will throw an error.
Observable state of holder(s) of lock(s). The W returns a pair of Ints where the first is number of read locks (at least 0) and the second is the number of write locks held (at least 1). The R returns a map from thread id to the number of read locks held (at least 1).
Much safer replacement for QSemN, QSem, and SampleVar This provides a much safer semaphore than the QSem, QSemN, SampleVar in base. Those base modules are not exception safe and can be broken by killThread. See https://github.com/ChrisKuklewicz/SafeSemaphore for more details.
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.
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.
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.
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.