
A safer gimmick... Ben Franksen wrote:
tickWhileDoing :: String -> IO a -> IO a tickWhileDoing msg act = do hPutStr stderr msg >> hPutChar stderr ' ' >> hFlush stderr start_time <- getCPUTime tickerId <- forkIO ticker
... an async exception here will leave the ticker runnning....
res <- act `finally` killThread tickerId
The best way to make this safe that I know of is:
res <- block $ do tickerId <- forkIO ticker unblock act `finally` killThread tickerId
stop_time <- getCPUTime let time_diff = realToFrac (stop_time - start_time) / 1e12 hPutStrLn stderr $ " done (took us " ++ show time_diff ++ " seconds)" return res where ticker = do hPutChar stderr '.' >> hFlush stderr threadDelay 100000 {-microsec-} ticker
I think nobody in his right mind would even try to do something like that in C or Perl or whatever, at least not if it wasn't strictly a requirement and correct operation is important (the script gets executed as part of our build process and a subtle concurrency bug could lead to a wrong configuration for the target control system). In Haskell it was so easy to do that I just couldn't resist.
Cheers Ben
PS (completely off-topic, sorry): I've been using the collections library throughout the project & I must say it is a lot nicer to work with than the base library mumble-jumble of duplicate interfaces, qualified imports and whatnot. The only disadvantages are that the API is not yet as complete as e.g. Data.Map, and that I have to manually hide name-clashing Prelude functions in almost every module. Many thanks to Jean-Philippe Bernardy for pioneering this work.