{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeOperators #-}
module Concurrent where
import Prelude hiding (break)
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative
#endif
import Language.Embedded.Imperative
import Language.Embedded.Concurrent
import Language.Embedded.CExp
type L =
ThreadCMD :+:
ChanCMD CExp :+:
ControlCMD CExp :+:
FileCMD CExp
-- | Deadlocks due to channel becoming full.
deadlock :: Program L ()
deadlock = do
c <- newChan 1
t <- fork $ readChan c >>= printf "%d\n"
writeChan c (1 :: CExp Int32)
writeChan c 2
writeChan c 3
printf "This never happens: %d\n" (4 :: CExp Int32)
-- | Map a function over a file, then print the results. Mapping and printing
-- happen in separate threads.
mapFile :: (CExp Float -> CExp Float) -> FilePath -> Program L ()
mapFile f i = do
c1 <- newCloseableChan 5
c2 <- newCloseableChan 5
fi <- fopen i ReadMode
t1 <- fork $ do
while (return true) $ do
x <- readChan c1
readOK <- lastChanReadOK c1
iff readOK
(void $ writeChan c2 (f x))
(closeChan c2 >> break)
t2 <- fork $ do
while (lastChanReadOK c2) $ do
readChan c2 >>= printf "%f\n"
t3 <- fork $ do
while (not_ <$> feof fi) $ do
fget fi >>= void . writeChan c1
fclose fi
closeChan c1
waitThread t2
-- | Waiting for thread completion.
waiting :: Program L ()
waiting = do
t <- fork $ printf "Forked thread printing %d\n" (0 :: CExp Int32)
waitThread t
printf "Main thread printing %d\n" (1 :: CExp Int32)
-- | A thread kills itself using its own thread ID.
suicide :: Program L ()
suicide = do
tid <- forkWithId $ \tid -> do
printf "This is printed. %d\n" (0 :: CExp Int32)
killThread tid
printf "This is not. %d\n" (0 :: CExp Int32)
waitThread tid
printf "The thread is dead, long live the thread! %d\n" (0 :: CExp Int32)