[Haskell-cafe] synchronous channels in STM

Arnar Birgisson arnarbi at gmail.com
Thu Oct 9 12:24:59 EDT 2008


On Thu, Oct 9, 2008 at 18:10, Arnar Birgisson <arnarbi at gmail.com> wrote:
>> But I did write a concurrent prime sieve with it:
>
> I did the same, with the one-place-buffers (the MVars implemented over
> STM). Be warned that there is no stop condition, this just keeps
> printing primes forever.

Please forgive me for reposting, but the last one exited quite prematurely :)


module Main where

import Control.Concurrent (forkIO)
import Control.Concurrent.STM
import System (getArgs)

-- MVars from the STM paper
type MVar a = TVar (Maybe a)

newEmptyMVar :: STM (MVar a)
newEmptyMVar = newTVar Nothing

takeMVar :: MVar a -> STM a
takeMVar mv
 = do v <- readTVar mv
      case v of
        Nothing  -> retry
        Just val -> do writeTVar mv Nothing
                       return val

putMVar :: MVar a -> a -> STM ()
putMVar mv val
 = do v <- readTVar mv
      case v of
        Nothing  -> writeTVar mv (Just val)
        Just _   -> retry

-- Sieve
forever a = do a; forever a

pfilter :: Int -> MVar Int -> MVar Int -> IO ()
pfilter p in_ out =
    forever $ do atomically $ do v <- takeMVar in_
                                 if v `mod` p /= 0
                                    then putMVar out v
                                    else return ()

sieve :: MVar Int -> MVar Int -> IO ()
sieve in_ out =
    do p <- atomically $ takeMVar in_
       atomically $ putMVar out p
       ch <- atomically $ newEmptyMVar
       forkIO $ pfilter p in_ ch
       sieve ch out

feeder :: MVar Int -> IO ()
feeder out = feed' 2
           where
             feed' i = do atomically $ putMVar out i
                          feed' (i+1)

printer :: MVar () -> MVar Int -> Int -> IO ()
printer stop in_ max =
    do v <- atomically $ takeMVar in_
       putStrLn $ show v
       if v > max then atomically $ putMVar stop ()
                  else printer stop in_ max

main :: IO ()
main = do max:_ <- getArgs
          in_ <- atomically newEmptyMVar
          out <- atomically newEmptyMVar
          stop <- atomically newEmptyMVar
          forkIO $ feeder in_
          forkIO $ printer stop out (read max)
          forkIO $ sieve in_ out
          atomically $ takeMVar stop
          return ()


More information about the Haskell-Cafe mailing list