code: def thread_handler(program):
      """Runs the threads and wraps them in Worker Manager."""
      if lp_flags.LP_WORKER_MANAGER_V2.value:
          manager = worker_manager_v2.WorkerManager(
              kill_all_upon_sigint=True,
          )
      else:
          manager = worker_manager.WorkerManager()
      for label, nodes in program.groups.items():
          # to_executables() is a static method, so we can call it from any of the
          # nodes in this group.
          # Somehow pytype thinks to_executables() gets wrong arg count.
          # pytype: disable=wrong-arg-count
          executables = nodes[0].to_executables(
              nodes, label, nodes[0].launch_context
          )
          # pytype: enable=wrong-arg-count
          for executable in executables:
              manager.thread_worker(label, executable)
  
      if sys.version_info[:2] >= (3, 9):
          # Make sure `manager.wait` will be called before ThreadPoolExecutor atexit
          # method. Otherwise running program will not be able to start new threads.
          futures.ThreadPoolExecutor
  
          threading._register_atexit(
              manager.wait
          )  # pytype: disable=module-attr  # py39-upgrade
  
      else:
          atexit.register(manager.wait)
  
      return manager
  
file_path: launchpad/launchpad/launch/local_multi_threading/launch.py
imports: import atexit
  from concurrent import futures
  import sys
  import threading
  from typing import Optional
  from absl import flags
  from launchpad import context
  from launchpad import flags
  from launchpad import program
  from launchpad.launch import serialization
  from launchpad.launch import worker_manager
  from launchpad.launch import worker_manager_v2
label_desc: Use image node_id 2 for calling a global function with example usage: thread_handler(program) and returns: manager