text: thread-hierarchy
  Simple Haskell thread management in hierarchical manner
  See all snapshots
  thread-hierarchy appears in
  thread-hierarchy-0.3.0.2@sha256:2766cd25775ed113c7ca5e03a0ffd2c838689b8f9b865d35d8925a9512b75ce1,1779
  Module documentation for 0.3.0.2
  - Control
  - Control.Concurrent
  thread-hierarchy
  Managing Haskell threads in hierarchical manner.
  Overview
  This package provides parent-child association and guaranteed clean-up of children over plain Haskell thread. You can terminate all child threads and grand child threads by just killing their parent thread.
  Motivation
  Unlike Unix process, plain Haskell thread, created by forkIO, has no parent-child relation each other. continue simple replacement API over plain forkIO in case of when all you need to do on parent termination is just terminating all its children.
  If you need to keep your child running after parent terminated, this API is not for you.
  Why not withAsync?
  The typical use case for this package is TCP server style use case. In such use case, you have to create virtually infinite number of threads and they finish in random timing but you are not so interested in their return value..
  Bellow explains why
  withAsync is not good for managing large number of threads.
  withAsync is essentially a sugar over bracket pattern like this.
  withAsync action inner = bracket (async action) uninterruptibleCancel inner
  It guarantees
  uninterruptibleCancel to the
  action is executed on asynchronous exception let async action go and make recursive call form
  inner back to your loop?
  It is a bad idea. Because
  withAsync is a
  bracket, recursive call from
  inner makes
  non-tail-recurse call.
  In other words, the difference between
  withAsync and
  newChild is strategy of un-installing
  cleanup handler.
  withAsync uninstalls its cleanup handler based on its lexical scope.
  newChild uninstalls it based on actual dynamic thread termination.
  Usage
  Almost all you need to know is one data type and one function:
  ThreadMap and
  newChild.
  Threads created by
  newChild guarantee automatic cleanup on its exit
  regardless normal exit or cancellation by asynchronous exception.
  In order to that works properly, user must ensure following rules.
  - User provided thread handler must accept
  ThreadMapas its first argument.
  - When the user provided handler creates its child thread, it must use newChild with given
  ThreadMap.
  - For 1st thread you create by newChild, give it a
  ThreadMapcreated by
  newThreadMap.
  ThreadMap is house-keeping object for your thread. It is a mutable map keeping track
  living child threads of your thread. When your thread handler started, you receives
  an empty
  ThreadMap via 1st argument of your handler. When you create a child thread
  of your thread,
  newChild automatically update (mutate) your
  ThreadMap by adding
  newly created child thread. When your child thread terminated, it is automatically removed
  from your
  ThreadMap.
  Same manner is applied to child thread and grandchild thread as long as you follow the rule the above.
  How it works
  When
  newChild creates a new thread, it installs two cleanup tasks for you.
  - Killing all thread contained in
  ThreadMapof the new thread. It kills all children of the new thread.
  - Removing the new thread itself from parent’s
  ThreadMap.
  The cleanup tasks are called when the new thread exit normally or terminated by asynchronous exception. By this mechanism, termination of top level thread is propagated down to all its children, children of children, and so on.
  Example
  When you create the first thread managed by this module, create a new empty
  ThreadMap then call
  newChild with it. The newCall automatically install cleanup routine to the handler you provided.
  createRootThread :: IO ThreadId createRootThread = do rootThreadMap <- newThreadMap threadID <- newChild rootThreadMap rootThreadHandler return threadID
  When a thread managed by this module creates its child thread, call newChild with
  TreadMap
  received via handlers argument.
  rootThreadHandler :: ThreadMap -> IO () rootThreadHandler myChildrenThreadMap = do void $ newChild myChildrenThreadMap $ \grandChildrenThreadMap -> do yourCode return ()
  You can install your own cleanup routine using finally or both resource acquisition and cleanup routine using bracket.
  -- Forking a new child with your own cleanup void $ newChild childrenOfCurrentThread $ \childrenOfHandler -> yourThreadHandler `finally` yourCleanupRoutine -- Forking a new child with resource acquisition and cleanup void $ newChild childrenOfCurrentThread $ \childrenOfHandler -> bracket yourResourceAcquiringRoutine yourCleanupRoutine yourThreadHandler
  Limitation
  Currently, unlike async function, this module is not designed to back any return value from child thread to parent thread. This module focuses on guaranteed cleanup on thread termination.
  Changes
  Thread-hierarchy 0.3.0.2
  - Include .cabal file in source repo.
  - Migrate CI from Travis to GitHub Actions.
  - Build and test for multiple platforms and GHC versions.
  Thread-hierarchy 0.3.0.1
  - Move to hpack from hand written cabal project file
  Thread-hierarchy 0.3.0.0
  - Back to basic. Unlifted APIs to IO.
  Thread-hierarchy 0.2.0.0
  - Improved implementation of previous fix.
  - No longer expose constructor of ThreadMap.
  Thread-hierarchy 0.1.0.3
  - Fixed BlockedIndefinitelyOnMVar under race condition.
  Thread-hierarchy 0.1.0.2
  - Fixed space leaks in map operation.
  Thread-hierarchy 0.1.0.1
  - Timing dependencies are removed from tests.
  Thread-hierarchy 0.1.0.0
  - Initial release.