shang
shang

Reputation: 24832

What is a reliable way to check if a thread is still running?

I'm currently using essentially the following code to start worker threads.

import Control.Monad      (void)
import Control.Concurrent (forkIO)
import Control.Exception  (finally)
import Data.IORef         (newIORef, writeIORef, readIORef)

startWorker :: IO a -> IO (IO Bool)
startWorker work = do
    running <- newIORef True
    _ <- forkIO $ void work `finally` writeIORef running False
    return $ readIORef running

I.e. start doing some work on the background and return an IO action that lets the caller poll if the worker thread is still running or if it has stopped for some reason.

How reliable is this method? Are there any situations where the thread would die without calling the finally block (excluding, of course, situations where the whole process is killed)? Is there a better way to achieve the same functionality?

Upvotes: 6

Views: 550

Answers (2)

Danny Navarro
Danny Navarro

Reputation: 2763

Related to Yuras' answer, there may be some issues with the initial masking state as it's explained in Mask and forkIO section of Simon Marlow's book. The bottom line, as he explains, is:

The rule of thumb is that any exception-handling function called as the first thing in a forkIO is better written using forkFinally. In particular, if you find yourself writing forkIO (xfinallyy), then write forkFinally x (\_ -> y) instead. Better still, use the Async API, which handles these details for you.

Upvotes: 5

Yuras
Yuras

Reputation: 13876

Async exception could fire after the thread is created, but before "void work `finally` writeIORef running False" is started. Use forkFinally to handle that.

I can imaging that there are other issues. I'd recommend async library. It handles all the complexity for you. Use poll to check Async status.

Upvotes: 7

Related Questions