Michael Lafayette
Michael Lafayette

Reputation: 3072

Haskell get set thread name

When I print something in Java, I usually append the name of the thread to the print statement so I know what thread is running what print statement. How do I get and set the thread name in Haskell? If I can't set the thread name, how do I make a thread that has a given name?

Note: I usually give my threads descriptive names like "GUI_thread", "main_thread", "database_thread", etc

Upvotes: 4

Views: 535

Answers (1)

Random Dev
Random Dev

Reputation: 52280

As I said in a comment you can use labelThread to give the thread a label. Sadly I could not find a way to pull this label back out (all I found was this invalid ticket where someone wanted to do just this).

But as descriped in Parallel and Concurrent Programming in Haskell you can get an event-log view on this:

(straight from there – I hope nobody minds):

main = do
  t <- myThreadId
  labelThread t "main"
  m <- newEmptyMVar
  t <- forkIO $ putMVar m 'a'
  labelThread t "a"
  t <- forkIO $ putMVar m 'b'
  labelThread t "b"
  traceEventIO "before takeMVar"
  takeMVar m
  takeMVar m

You then should compile it with the threaded and eventlog switches set:

ghc mvar4.hs -threaded -eventlog

and can call it with +RTS and -l:

./mvar4 +RTS -l

Finally you can look at the output with ghc-evetns:

ghc-events show mvar4.eventlog

Naive self-implementation

That seems not to be exactly what you want, so here is a (very basic) example of how you could do it yourself (using just lists and an MVar to keep the association between the ThreadId and its name):

import Control.Concurrent

type Labels = MVar [(ThreadId, String)]

initLabels :: IO Labels
initLabels = newMVar []

labelThread :: Labels -> ThreadId -> String -> IO ()
labelThread labels threadId label =
  modifyMVar_ labels (\assocs -> return $ (threadId, label):assocs)

getLabel :: Labels -> ThreadId -> IO String
getLabel labels threadId = withMVar labels (\assocs ->
  case lookup threadId assocs of
    Just label -> return label
    Nothing    -> return $ show threadId)

and you can use it like this:

main :: IO ()
main = do
  ls <- initLabels
  myId <- myThreadId
  getLabel ls myId >>= print
  labelThread ls myId "my Thread"
  getLabel ls myId >>= print

which would get you:

λ> :main
"ThreadId 50"
"my Thread"

Obviously this might not be a good idea if you create lots of threads. At the very least you should add something to remove the label again at the end of your thread:

removeLabel :: Labels -> ThreadId -> IO ()
removeLabel labels threadId =
  modifyMVar_ labels (return . filter ((/= threadId) . fst))

forkLabeledIO :: Labels -> String -> IO () -> IO ThreadId
forkLabeledIO labels label computation = forkIO $ do
  myId <- myThreadId
  labelThread labels myId label
  computation
  removeLabel labels myId

... yeah I know: nasty – and of course a Map might be a better idea too – but I hope you get the basic idea

Upvotes: 5

Related Questions