
Jules Bean wrote:
ChrisK wrote:
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
...but with a change that Simon M just checked in to GHC head, this will now spawn 'ticker' in blocked state, so you won't be able to kill it. You would therefore want unblock $ forkIO ticker or forkIO $ unblock ticker
I'm not sure if there is a strong reason to prefer one over the other.
Jules
That is new. Ah, I see GHC.Conc.forkIO now has a note:
GHC note: the new thread inherits the /blocked/ state of the parent (see 'Control.Exception.block').
BUT...doesn't this change some of the semantics of old code that used forkIO ? I wanted a way to control the blocked status of new threads, since this makes it easier to be _sure_ some race conditions will never happen. And so my new preferred way of writing this is now:
-- we are in parent's blocked state, so make the ticker explicit: res <- bracket (forkIO (unblock ticker)) killThread const act -- act runs in parent's blocked state
-- Chris