Title here
Summary here
Basic sends and receives on channels are blocking in concurrent Haskell programs. However, we can use tryReadChan
and tryWriteChan
to implement non-blocking operations on channels.
import Control.Concurrent.Chan
import Control.Concurrent
import System.IO
main :: IO ()
main = do
messages <- newChan
signals <- newChan
-- Here's a non-blocking receive. If a value is
-- available on `messages` then `tryReadChan` will
-- return `Just` that value. If not, it will
-- return `Nothing`.
result <- tryReadChan messages
case result of
Just msg -> putStrLn $ "received message " ++ msg
Nothing -> putStrLn "no message received"
-- A non-blocking send works similarly. Here `msg`
-- is attempted to be sent to the `messages` channel.
-- `tryWriteChan` returns `True` if the write was successful,
-- and `False` otherwise.
let msg = "hi"
success <- tryWriteChan messages msg
if success
then putStrLn $ "sent message " ++ msg
else putStrLn "no message sent"
-- We can use multiple `tryReadChan` calls to implement
-- a multi-way non-blocking select. Here we attempt
-- non-blocking receives on both `messages` and `signals`.
resultMessages <- tryReadChan messages
resultSignals <- tryReadChan signals
case (resultMessages, resultSignals) of
(Just msg, _) -> putStrLn $ "received message " ++ msg
(_, Just sig) -> putStrLn $ "received signal " ++ show sig
_ -> putStrLn "no activity"
To run the program:
$ runhaskell non_blocking_channel_operations.hs
no message received
no message sent
no activity
In this Haskell version:
Control.Concurrent.Chan
for channel operations.tryReadChan
is used for non-blocking reads. It returns Maybe a
where a
is the channel’s type.tryWriteChan
is used for non-blocking writes. It returns a Bool
indicating success or failure.select
statement in the original code.tryReadChan
operations and use pattern matching to handle all cases.Note that Haskell’s approach to concurrency is different from some other languages. It uses lightweight threads and Software Transactional Memory (STM) for more complex concurrent operations, which can provide safer and more composable concurrency primitives.