Starts the job. If the job was run once before, resets it completely. Can
    not be used while the job is running (raises #InvalidState).

    # Arguments
    as_thread (bool): Start the job in a separate thread. This is #True by
      default. Classes like the #ThreadPool calls this function from its own
      thread and passes #False for this argument.
    daemon (bool): If a thread is created with *as_thread* set to #True,
      defines whether the thread is started as a daemon or not. Defaults to
      #False.

    # Returns
    Job: The job object itself.

def start(self, as_thread=True, daemon=False, __state_check=True):
    """
    Starts the job. If the job was run once before, resets it completely. Can
    not be used while the job is running (raises #InvalidState).

    # Arguments
    as_thread (bool): Start the job in a separate thread. This is #True by
      default. Classes like the #ThreadPool calls this function from its own
      thread and passes #False for this argument.
    daemon (bool): If a thread is created with *as_thread* set to #True,
      defines whether the thread is started as a daemon or not. Defaults to
      #False.

    # Returns
    Job: The job object itself.
    """

    if __state_check:
      # We need to manually manage the lock to be able to release it
      # pre-emptively when needed.
      with synchronized(self):
        if self.__cancelled and self.__state == Job.PENDING:
          # Cancelled in PENDING state. Do not run the target function at all.
          self.__state = Job.CANCELLED
          assert self.__exception is None
          assert self.__result is None
          self._trigger_event(Job.CANCELLED)
          return None

        if self.__state == Job.RUNNING:
          raise Job.InvalidState('job is already running')
        elif self.__state not in (Job.PENDING, Job.ERROR, Job.SUCCESS, Job.CANCELLED):
          raise RuntimeError('invalid job state {0!r}'.format(self.__state))

        # Reset the Job attributes.
        self.__state = Job.RUNNING
        self.__cancelled = False
        self.__result = None
        self.__exception = None
        self.__event_set.clear()
        self.__thread = None

        # Remove all listeners that have been registered with the "once" flag.
        for listeners in self.__listeners.values():
          listeners[:] = (l for l in listeners if not l.once)

    if as_thread:
      thread = threading.Thread(target=self.start, args=(False, False, False))
      thread.setDaemon(daemon)
      with synchronized(self):
        assert not self.__thread or not self.__thread.running
        self.__thread = thread
      thread.start()
      return self

    try:
      result = None
      exception = None
      try:
        result = self.run()
        state = Job.SUCCESS
      except Exception:  # XXX: Catch BaseException?
        if self.print_exc:
          traceback.print_exc()
        exception = Job.ExceptionInfo(*sys.exc_info())
        state = Job.ERROR

      with synchronized(self):
        cancelled = self.__cancelled
        self.__result = result
        self.__exception = exception
        self.__state = Job.CANCELLED if cancelled else state

      self._trigger_event(state)
    finally:
      with synchronized(self):
        notify_all(self)
      if self.__dispose_inputs:
        self.__target = None
        self.__args = None
        self.__kwargs = None
        self.data = None
        for listeners in self.__listeners.values():
          listeners[:] = []

    return self