code: def join(self, timeout=None):
          
          if not self.__initialized:
              raise RuntimeError("Thread.__init__() not called")
          if not self.__started.is_set():
              raise RuntimeError("cannot join thread before it is started")
          if self is current_thread():
              raise RuntimeError("cannot join current thread")
  
          if __debug__:
              if not self.__stopped:
                  self._note("%s.join(): waiting until thread stops", self)
          self.__block.acquire()
          try:
              if timeout is None:
                  while not self.__stopped:
                      self.__block.wait()
                  if __debug__:
                      self._note("%s.join(): thread stopped", self)
              else:
                  deadline = _time() + timeout
                  while not self.__stopped:
                      delay = deadline - _time()
                      if delay <= 0:
                          if __debug__:
                              self._note("%s.join(): timed out", self)
                          break
                      self.__block.wait(delay)
                  else:
                      if __debug__:
                          self._note("%s.join(): thread stopped", self)
          finally:
              self.__block.release()
docs: Wait until the thread terminates.
  
          This blocks the calling thread until the thread whose join() method is
          called terminates -- either normally or through an unhandled exception
          or until the optional timeout occurs.
  
          When the timeout argument is present and not None, it should be a
          floating point number specifying a timeout for the operation in seconds
          (or fractions thereof). As join() always returns None, you must call
          isAlive() after join() to decide whether a timeout happened -- if the
          thread is still alive, the join() call timed out.
  
          When the timeout argument is not present or None, the operation will
          block until the thread terminates.
  
          A thread can be join()ed many times.
  
          join() raises a RuntimeError if an attempt is made to join the current
          thread as that would cause a deadlock. It is also an error to join() a
          thread before it has been started and attempts to do so raises the same
          exception.