BoundedChan (empty) → 1.0.0.0
raw patch · 3 files changed
+99/−0 lines, 3 filesdep +arraydep +basesetup-changed
Dependencies added: array, base
Files
- BoundedChan.cabal +20/−0
- Control/Concurrent/BoundedChan.hs +77/−0
- Setup.hs +2/−0
+ BoundedChan.cabal view
@@ -0,0 +1,20 @@+name: BoundedChan+category: Concurrency+version: 1.0.0.0+license: BSD3+author: Adam Wick <awick@galois.com>+maintainer: Adam Wick <awick@galois.com>+stability: stable+build-type: Simple+cabal-version: >= 1.6+tested-with: GHC ==6.10+synopsis: Implementation of bounded Chans.+description: This library introduces BoundedChan. BoundedChan works exactly+ like Chan -- and, indeed, has the exact same interface -- but+ is guaranteed to operate in a bounded amount of space.++Library+ build-depends: base >= 3, array+ exposed-modules: Control.Concurrent.BoundedChan+ GHC-Options: -O2 -Wall -funbox-strict-fields+
+ Control/Concurrent/BoundedChan.hs view
@@ -0,0 +1,77 @@+-- |Implements bounded channels. In these channels, you can give a+-- rough maximum number of elements, and you will be guaranteed that no more+-- than that number of elements will be pending within the channel.+--+-- This boundedness is ideal when you will be (or may be) writing to a channel+-- faster than you are able to read from it.+--+-- This module supports all the functions of Control.Concurrent.Chan except+-- unGetChan and dupChan, which are not supported for bounded channels.+module Control.Concurrent.BoundedChan(+ BoundedChan+ , newBoundedChan+ , writeChan+ , readChan+ , isEmptyChan+ , getChanContents+ , writeList2Chan+ )+ where++import Control.Concurrent.MVar+import Control.Monad(replicateM)+import Data.Array+import System.IO.Unsafe(unsafeInterleaveIO)++-- |BoundedChan is an abstract data type representing an unbounded channel.+data BoundedChan a = BC {+ _size :: Int+ , _contents :: Array Int (MVar a)+ , _writePos :: MVar Int+ , _readPos :: MVar Int+ }+-- LOCK ORDERING: A -> B -> C++-- |Create a new bounded chan with size n. +newBoundedChan :: Int -> IO (BoundedChan a)+newBoundedChan x = do+ entls <- replicateM x newEmptyMVar+ wpos <- newMVar 0+ rpos <- newMVar 0+ let entries = listArray (0, x - 1) entls+ return (BC x entries wpos rpos)++-- |Write an element to the channel. If the channel is full, this routine will+-- block until it is able to write. If you have multiple writers, be careful+-- here, because the unlocking is not guaranteed to avoid starvation.+writeChan :: BoundedChan a -> a -> IO ()+writeChan (BC size contents wposMV _) x = do+ wpos <- takeMVar wposMV+ putMVar wposMV $! (wpos + 1) `mod` size+ putMVar (contents ! wpos) x++-- |Read an element from the channel. If the channel is empty, this routine +-- will block until it is able to read.+readChan :: BoundedChan a -> IO a+readChan (BC size contents _ rposMV) = do+ rpos <- takeMVar rposMV+ putMVar rposMV $! (rpos + 1) `mod` size+ takeMVar (contents ! rpos)++isEmptyChan :: BoundedChan a -> IO Bool+isEmptyChan (BC _ contents _ rposMV) = do+ rpos <- takeMVar rposMV+ res <- isEmptyMVar (contents ! rpos)+ putMVar rposMV rpos+ return res++getChanContents :: BoundedChan a -> IO [a]+getChanContents ch = unsafeInterleaveIO $ do+ x <- readChan ch+ xs <- getChanContents ch+ return (x:xs)++-- |Write a list of elements to the channel. Note that this may block as it+-- writes the list into the channel.+writeList2Chan :: BoundedChan a -> [a] -> IO ()+writeList2Chan ch ls = mapM_ (writeChan ch) ls
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain