interprocess-0.2.0.0: examples/wait-qsem.hs
module Main where
import Control.Concurrent (threadDelay)
import Control.Concurrent.Process.QSem
import Control.Monad
import Data.List (partition)
import Data.Maybe (fromMaybe)
import Data.Monoid (First (..))
import Foreign.SharedObjectName
import System.Environment
import System.IO
import System.Process.Typed
import Text.Read (readMaybe)
main :: IO ()
main = do
args <- getArgs
let (isSlaveL, remargs) = partition ("slave"==) args
isSlave = not $ null isSlaveL
n = fromMaybe 4 . getFirst $ foldMap (First . readMaybe) remargs
if isSlave
then runB
else runA n
runA :: Int -> IO ()
runA n = do
execFile <- getExecutablePath
args <- getArgs
let processBConfig = setStdin createPipe
$ proc execFile ("slave":args)
putStrLn "[A] Starting..."
withNProcesses n processBConfig $ \procs -> do
qSem <- newQSem 0
forM_ (zip [99 :: Int, 98..] procs) $ \(i, p) -> do
hPutSOName (getStdin p) (qSemName qSem)
hPrint (getStdin p) $ 100 - i
hPutStrLn (getStdin p) $ "Say " ++ show i ++ " bottles of rum!"
hFlush (getStdin p)
threadDelay 100000
putStrLn "[A] Done! Signal semaphore available to other threads"
replicateM_ n $ threadDelay 100000 >> signalQSem qSem
putStrLn "[A] Finished successfully"
runB :: IO ()
runB = do
let inputH = stdin
Just qSemRef <- hGetSOName inputH -- get name of a semaphore
qSem <- lookupQSem qSemRef
i <- read <$> hGetLine inputH -- get id of a spawned process
instruction <- hGetLine inputH -- some arbitrary text
putStrLn $ "[B] " ++ instruction
threadDelay 500000
if mod i 7 == (2 :: Int)
then
let procedure = do
wasAvailable <- tryWaitQSem qSem
if wasAvailable
then
putStrLn $ "[B] (" ++ show i ++ ") Was available - " ++ reverse instruction
else do
putStrLn $ "[B] (" ++ show i ++ ") Ha-ha, I am not blocked!"
waitQSem qSem
putStrLn $ "[B] (" ++ show i ++ ") Woke up"
signalQSem qSem
threadDelay 100000
procedure
in procedure
else do
waitQSem qSem
putStrLn $ "[B] " ++ reverse instruction
putStrLn "[B] Finished successfully"
withNProcesses :: Int
-> ProcessConfig stdin stdout stderr
-> ([Process stdin stdout stderr] -> IO a)
-> IO a
withNProcesses 0 _ k = k []
withNProcesses n conf k = withProcess_ conf $ \p ->
withNProcesses (n-1) conf (k . (p:))