docstr: Join one or more processes within spawn context.
  
  Attempt to join one or more processes in this spawn context.
  If one of them exited with a non-zero exit status, this function
  kills the remaining processes and raises an exception with the cause
  of the first process exiting.
  
  Returns ``True`` if all processes have been joined successfully,
  ``False`` if there are more processes that need to be joined.
  
  Args:
      timeout (float): Wait this long before giving up on waiting.
docstr_tok: ["Join","one","or","more","processes","within","spawn","context",".","Attempt","to","join","one","or","more","processes","in","this","spawn","context",".","If","one","of","them","exited","with","a","non-zero","exit","status",",","this","function","kills","the","remaining","processes","and","raises","an","exception","with","the","cause","of","the","first","process","exiting",".","Returns","``","True","``","if","all","processes","have","been","joined","successfully",",","``","False","``","if","there","are","more","processes","that","need","to","be","joined",".","Args",":","timeout","(","float",")",":","Wait","this","long","before","giving","up","on","waiting","."]
code: def join(self, timeout=None):
      r"""Join one or more processes within spawn context.
  
      Attempt to join one or more processes in this spawn context.
      If one of them exited with a non-zero exit status, this function
      kills the remaining processes and raises an exception with the cause
      of the first process exiting.
  
      Returns ``True`` if all processes have been joined successfully,
      ``False`` if there are more processes that need to be joined.
  
      Args:
          timeout (float): Wait this long before giving up on waiting.
      """
      # Ensure this function can be called even when we're done.
      if len(self.sentinels) == 0:
          return True
  
      # Wait for any process to fail or all of them to succeed.
      ready = multiprocessing.connection.wait(
          self.sentinels.keys(),
          timeout=timeout,
      )
  
      error_index = None
      for sentinel in ready:
          index = self.sentinels.pop(sentinel)
          process = self.processes[index]
          process.join()
          if process.exitcode != 0:
              error_index = index
              break
  
      # Return if there was no error.
      if error_index is None:
          # Return whether or not all processes have been joined.
          return len(self.sentinels) == 0
  
      # Assume failure. Terminate processes that are still alive.
      # Try SIGTERM then SIGKILL if the process isn't going down.
      # The reason is related to python signal handling is limited
      # to main thread and if that is in c/c++ land and stuck it won't
      # to handle it. We have seen processes getting stuck not handling
      # SIGTERM for the above reason.
      timeout: int = 30
      for process in self.processes:
          if process.is_alive():
              log.warning(
                  "Terminating process %s via signal SIGTERM",
                  process.pid,
              )
              process.terminate()
      end = time.monotonic() + timeout
      for process in self.processes:
          time_to_wait = max(0, end - time.monotonic())
          process.join(time_to_wait)
      for process in self.processes:
          if process.is_alive():
              log.warning(
                  "Unable to shutdown process %s via SIGTERM , forcefully exiting via SIGKILL",
                  process.pid,
              )
              process.kill()
          process.join()
  
      # The file will only be created if the process crashed.
      failed_process = self.processes[error_index]
      if not os.access(self.error_files[error_index], os.R_OK):
          exitcode = self.processes[error_index].exitcode
          if exitcode < 0:
              try:
                  name = signal.Signals(-exitcode).name
              except ValueError:
                  name = f"<Unknown signal {-exitcode}>"
              raise ProcessExitedException(
                  "process %d terminated with signal %s"
                  % (error_index, name),
                  error_index=error_index,
                  error_pid=failed_process.pid,
                  exit_code=exitcode,
                  signal_name=name,
              )
          else:
              raise ProcessExitedException(
                  "process %d terminated with exit code %d"
                  % (error_index, exitcode),
                  error_index=error_index,
                  error_pid=failed_process.pid,
                  exit_code=exitcode,
              )
  
      with open(self.error_files[error_index], "rb") as fh:
          original_trace = pickle.load(fh)
      msg = (
          "\n\n-- Process %d terminated with the following error:\n"
          % error_index
      )
      msg += original_trace
      raise ProcessRaisedException(msg, error_index, failed_process.pid)
  
imports: import logging
  import multiprocessing
  import multiprocessing.connection
  import os
  import pickle
  import signal
  import sys
  import tempfile
  import time
  import warnings
  from typing import Optional
  from .None import _prctl_pr_set_pdeathsig
label_desc: Use image node_id 3 for calling the ProcessContext obj's underlying member method code with example usage: obj.join(timeout) and returns: True, unknown