Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I manually kill a thread?

Tags:

haskell

I'm in ghci testing some functions that fork threads, kinda like this:

myForkingFunction = do
  tid <- forkIO (workerFunction)
  putStrLn ("Worker thread: " ++ show tid)
  putStrLn ("...lots of other actions...")

  where workerFunction = do 
          putStrLn "In real life I'm listening for jobs...."
          workerFunction

This results in:

🐢  > myForkingFunction
Worker thread: ThreadId 216
...lots of other actions...
🐢  > In real life I'm listening for jobs....
In real life I'm listening for jobs....
In real life I'm listening for jobs....
In real life I'm listening for jobs....

(and so on)

Then as I'm :r-ing and iterating on the code, I notice that even when I reload, my workerFunction is still going.

So, I thought could just look at the printed output and do killThread (ThreadId 234) or whatever.

But first, I need to import ThreadId(..) from GHC.Conc.Sync?

Then I get this error:

<interactive>:110:22: error:
    • Couldn't match a lifted type with an unlifted type
      When matching types
        Integer :: *
        GHC.Prim.ThreadId# :: TYPE 'GHC.Types.UnliftedRep
    • In the first argument of ‘ThreadId’, namely ‘805’
      In the first argument of ‘killThread’, namely ‘(ThreadId 805)’
      In the expression: killThread (ThreadId 805)

So I think I must be approaching this wrong?

like image 560
Libby Avatar asked Mar 06 '23 06:03

Libby


2 Answers

I don't think there's any way to construct a ThreadId (e.g. from the result of show). See this question so you'll need to hold on to the ThreadId returned from forkIO, e.g. by changing your function to:

myForkingFunction = do
  tid <- forkIO (workerFunction)
  putStrLn ("Worker thread: " ++ show tid)
  putStrLn ("...lots of other actions...")
  return tid

and doing in ghci:

> tid <- myForkingFunction
> killThread tid

The error you get is a little confusing, and I believe has to do with the fact that numeric literals (like 216) are polymorphic; the argument to ThreadId is ThreadId# which is an unlifted type so you get the error you see before the compiler can even complain of "no instance Num ThreadId#"

like image 165
jberryman Avatar answered Mar 10 '23 21:03

jberryman


ThreadId values are treated specially by the runtime. You can't just create one. You need access to a ThreadId either as produced by forkIO when creating the thread or by myThreadId inside the thread.

Just for extra fun, threads don't get garbage collected while any ThreadId from one is still reachable. So you can't just hold on to them in case you need them. You need to actually have a plan to manage threads.

I think you're probably best off using the async library and it's various linking operations to ensure that when the parent thread is killed, it also kills all its child threads. It's a little (or a lot) of an awkward code style, but it's the best way to get correct behavior.

like image 40
Carl Avatar answered Mar 10 '23 20:03

Carl