
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