Hi,
Einar Wolfgang Karlsen writes:
>
> Consider the following Concurrent Haskell program where a reader
> thread is forked off to wait for input over the reading end of a
> pipe. The main thread attempts after a while to close this
> file descriptor.
>
> module Main (
> main
> ) where
>
> import Concurrent
> import Posix
> import PosixUtil
> import GlaExts
>
> main = do {
> (r,w) <- createPipe;
> forkIO (reader r);
> threadDelay 100000;
> print "closing pipes";
> try (fdClose r);
> try (fdClose w);
> threadDelay 100000;
> print "main thread done";
> return ()
> } where reader r = do {threadWaitRead (fdToInt r); return ()}
> fdToInt :: Fd -> Int
> fdToInt (FD# fd#) = I# fd#
> try c = catch (c >>= return . Right ) (return . Left)
>
Thanks for the tip, I've added fdToInt to PosixUtil (try is provided
by IO though.)
> The outcome of running this little program is that it aborts with:
>
> ewk@hydra% test1
> "closing pipes"
> AwaitEvent: select failed
> ewk@hydra%
>
> Personally I would find application development much easier if (1) the
> reader thread was simply garbage collected or (2) the suspended call to
> threadWaitRead failed with an error fdClosed or something like that.
> (2) is my personal choice since it would allow the reader thread to do
> some meaningful work in response to the error, but (1) is ok as well.
> However, aborting the whole program is far too extreme for my taste and
> the kind of applications that I develop (Unix client-server applications).
>
Hmm..there's a couple of things going on here:
- The Concurrent Haskell IO implementation isn't non-blocking.
- Hence you have to drop down to the level of file descriptors
and threadWaitRead&Write to work.
We're reluctant to add support at the level of file descriptors for
what you're suggesting, instead you should be able to write:
hCreatePipe :: IO (Handle, Handle)
main = do {
(r,w) <- hCreatePipe;
forkIO (reader r);
threadDelay 100000;
print "closing pipes";
try (hClose r);
try (hClose w);
threadDelay 100000;
print "main thread done";
return ()
} where reader r = do {hReady r; return ()}
using a non-blocking version of IO, that implicitly would deal with
the closing of handles that other threads are waiting for I/O on.
Are there cases where a Concurrent Haskell friendly implementation of
IO would fail to deliver the functionality you want?
--Sigbjorn