[Haskell] Waiting on multiple Chan-nels

Setzer, Sebastian (ext) sebastian.setzer.ext at siemens.com
Tue Dec 12 13:47:51 EST 2006

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"
		command '2' = do
			writeChan chan2 "main: 2"
		command '\n' = do -- ignore
		command c = do
			print ("illegal: " ++ [c])

-- 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
	- 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
	- 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
	  purpose. Unless you want every "event" to be handled only
	  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)

More information about the Haskell mailing list