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?
The isAlive() method of thread class tests if the thread is alive. A thread is considered alive when the start() method of thread class has been called and the thread is not yet dead. This method returns true if the thread is still running and not finished.
A Thread class is responsible for creating and managing a thread in multi-thread programming. It provides a property known as IsAlive to check if the thread is alive or not. Or in other words, the value of this property indicates the current execution of the thread.
The top command can show a real-time view of individual threads. To enable thread views in the top output, invoke top with "-H" option. This will list all Linux threads. You can also toggle on or off thread view mode while top is running, by pressing 'H' key.
Threads are created by implementing the runnable interface. The status of a thread can be retrieved by getState() method of the Thread class object.
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.
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 usingforkFinally
. In particular, if you find yourself writingforkIO (x
finallyy)
, then writeforkFinally x (\_ -> y)
instead. Better still, use the Async API, which handles these details for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With