Hi,
How do you wait on multiple channels, but read only from one of them
(the first that gets an entry)? Is there a library-function I missed
which already does this?

What do you think of this solution?

Sebastian Setzer
--------------------------------------------------------------

-- ghc chantest.hs -o chantest
-- Usage: Enter "1", "2" or "0" to exit.
import System.IO
import Control.Concurrent
import Control.Concurrent.Chan

main :: IO()
main = do
        chan1 <- newChan
        chan2 <- newChan
        c1Thread <- forkIO (printChan "c1" chan1)
        c2Thread <- forkIO (printChan "c2" chan2)
        c12Thread <- forkIO (printChannels "c12" [chan1, chan2])
        mainloop chan1 chan2

mainloop :: Chan String -> Chan String -> IO ()
mainloop  chan1 chan2 = do
                c <- getChar
                command  c
        where -- chan1 and chan2 are in scope, here.
                go_on :: IO()
                go_on = mainloop chan1 chan2                    
                
                command :: Char -> IO()
                command '0' = do
                        print "done"
                command '1' = do
                        writeChan chan1 "main: 1"
                        go_on
                command '2' = do
                        writeChan chan2 "main: 2"
                        go_on
                command '\n' = do -- ignore
                        go_on
                command c = do
                        print ("illegal: " ++ [c])
                        go_on

-- return microseconds
seconds :: Int -> Int
seconds = (* 1000000)

printChan :: String -> (Chan String) -> IO()
printChan name chan = do
        -- threadDelay (seconds 3)
        -- print (name ++ " ready")
        s <- readChan chan
        printString name s
        printChan name chan

printChannels :: String -> [Chan String] -> IO()
printChannels name channels = do
        -- select (zip channels (repeat (printString name)))
        select $ zip channels $ repeat $ printString name
        printChannels name channels
        
printString :: String -> String -> IO ()
printString name s = print (name ++ ": " ++ s)

select :: [(Chan a, a -> IO())] -> IO ()
select channel_handler_pairs = do
        threadDelay (seconds 3)
        print "TODO: implement select"
{-
        TODO: implement select.
        - create MVar
        - For each element of the channel_handler_pairs - list, fork a
thread.
        - wait on an MVar for the signal "I'm done"
        - kill all helper threads (just to free the resources. They
wouldn't do
          any harm)
        In the helper-threads:
        - readChan
        - try to signal "I'm ready" on the MVar.
          If another thread was faster, unGetChan and exit
        - call the handler
        - signal "I'm done" and exit
        
        Problems:
        - If the Thread gets killed between readChan and unGetChan, the
message is lost.
        - if another thread reads between readChan and unGetChan,
          its no fifo anymore (unlikely, because why would you want to
read with
          multiple threads on the same Chan? - You'd use dupChan for
that
          purpose. Unless you want every "event" to be handled only
once.
          But then you would'nt use multiple threads, would you?)
        - "a" must be the same for every channel-handler-pair
          Thats easy: instead of channel-handler-tuples, put functions
          MVar -> IO() into the list and provide a nice-looking operator
          to create them
        - Probably inefficient (lots of helper threads)
-}
_______________________________________________
Haskell mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell

Reply via email to