[Haskell-cafe] How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Benjamin Franksen benjamin.franksen at bessy.de
Wed Jan 18 14:59:28 EST 2006


On Wednesday 18 January 2006 19:01, Dimitry Golubovsky wrote:
> Is it possible to redirect a Handle (say stdout) somewhere only
> within a running thread (started with forkIO) not touching the same
> handle for the main and other threads?
>
> I have a lot of code written with putStr(Ln) which was used in a
> program acting as a filter, i. e. stdout was redirected by the
> invoking shell. Now I want to run this code within a thread in other
> program, but output must go to a file (or a pipe, or anywhere else a
> file descriptor may be opened for). So fdToHandle is not good because
> I need to modify the `stdout' only for that thread, not to create a
> new Handle. Rewriting the code is not a convenient way (but will be
> done if nothing else helps) because then I will need to pass that
> handle around.

Isn't this _the_ real-world example perfectly matching Robert Dockins' 
'threadlocal' proposal?

Anyway, I think you could hack your way around the problem:

  {-# NOINLINE special_tid_var #-}
  special_tid_var :: MVar ThreadId
  special_tid_var = unsafePeformIO newEmptyMVar

  {-# NOINLINE special_stdout_var #-}
  special_stdout_var :: MVar Handle
  special_stdout_var = unsafePeformIO newEmptyMVar

  main = do
    ...
    open File ... >>= putMVar special_stdout_var
    forkIO ... >>= putMVar special_tid_var
    ...

  -- replacement for the usual putStrLn
  putStrLn :: String -> IO ()
  putStrLn str = do
    mytid <- myThreadId
    special_tid <- readMVar special_tid_var
    specia_stdout <- readMVar special_stdout_var
    if mytid == special_tid
      then System.IO.hPutStrLn special_stdout str
      else System.IO.putStrLn str

Not tested, but you should get the idea. Caveat: you must change all 
your import declarations to hide System.IO.putStrLn and instead import 
the version above.

Ben


More information about the Haskell-Cafe mailing list