docs: def run(self):
          """ This defines the sequence of actions that are taken when the preemptive concurrency state is executed
  
          :return:
          """
          logger.debug("Starting execution of {0}{1}".format(self, " (backwards)" if self.backward_execution else ""))
          self.setup_run()
  
          try:
              concurrency_history_item = self.setup_forward_or_backward_execution()
              concurrency_queue = self.start_child_states(concurrency_history_item)
  
              #######################################################
              # wait for the first threads to finish
              #######################################################
              finished_thread_id = concurrency_queue.get()
              finisher_state = self.states[finished_thread_id]
              finisher_state.join()
  
              # preempt all child states
              if not self.backward_execution:
                  for state_id, state in self.states.items():
                      state.recursively_preempt_states()
              # join all states
              for history_index, state in enumerate(self.states.values()):
                  self.join_state(state, history_index, concurrency_history_item)
                  self.add_state_execution_output_to_scoped_data(state.output_data, state)
                  self.update_scoped_variables_with_output_dictionary(state.output_data, state)
  
              # add the data of the first state now to overwrite data of the preempted states
              self.add_state_execution_output_to_scoped_data(finisher_state.output_data, finisher_state)
              self.update_scoped_variables_with_output_dictionary(finisher_state.output_data, finisher_state)
              #######################################################
              # handle backward execution case
              #######################################################
              if self.states[finished_thread_id].backward_execution:
                  return self.finalize_backward_execution()
  
              else:
                  self.backward_execution = False
  
              #######################################################
              # handle no transition
              #######################################################
              transition = self.get_transition_for_outcome(self.states[finished_thread_id],
                                                           self.states[finished_thread_id].final_outcome)
              if transition is None:
                  # final outcome is set here
                  transition = self.handle_no_transition(self.states[finished_thread_id])
              # it the transition is still None, then the state was preempted or aborted, in this case return
              if transition is None:
                  self.output_data["error"] = RuntimeError("state aborted")
              else:
                  if 'error' in self.states[finished_thread_id].output_data:
                      self.output_data["error"] = self.states[finished_thread_id].output_data['error']
                  self.final_outcome = self.outcomes[transition.to_outcome]
  
              return self.finalize_concurrency_state(self.final_outcome)
  
          except Exception as e:
              logger.error("{0} had an internal error: {1}\n{2}".format(self, str(e), str(traceback.format_exc())))
              self.output_data["error"] = e
              self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
              return self.finalize(Outcome(-1, "aborted"))