Как предотвратить прерывание boost :: statetechart из-за сгенерированного исключения

0

Я реализовал машину состояний, которая наследует boost :: statechart. Когда я вызываю fsm.process_event( some_event() ) какая реакция, как ожидается, fsm.process_event( some_event() ) исключение, оказывается, что после обработки исключения с блоком try-catch мой экземпляр fsm завершается. То есть fsm.terminated() возвращает true. В некоторых случаях я не хочу, чтобы это прекращалось. Например, когда я хочу, чтобы fsm.process_event( irrelevant_event() ) исключение, чтобы сообщить вызывающему пользователю fsm.process_event( irrelevant_event() ) для не обработанного события и сохранить его текущий до состояния события.

Короче говоря, как я могу предотвратить завершение boost::statechart после того, как он выдает исключение и сохраняет его до состояния исключения?

Пример кода:

namespace sc = boost::statechart;
class State;
struct some_event : public sc::event<some_event> { };

class FSM
    : public sc::state_machine< FSM, State, std::allocator<void>, sc::exception_translator<> >
{
public:
    FSM()
    {
        cout<<"FSM::FSM()"<<endl;
    }
    virtual ~FSM()
    {
        cout<<"FSM::~FSM()"<<endl;
    }
};


class State : public sc::simple_state< State, FSM >
{
public:
    State()
    {
        cout<<"State::State()"<<endl;
    }
    virtual ~State()
    {
        cout<<"State::~State()"<<endl;
    }

    typedef boost::mpl::list<
        sc::custom_reaction< some_event >,
        sc::custom_reaction< sc::exception_thrown >
    > reactions;
    sc::result react( const some_event & e)
    {
        cout<<"State::react( const some_event &)"<<endl;
        throw std::exception();
        return this->discard_event();
    }
    sc::result react( const sc::exception_thrown & e)
    {
        cout<<"State::react( const sc::exception_thrown &)"<<endl;
        throw;
        return this->discard_event();
    }
};

int main()
{
    FSM fsm;
    fsm.initiate();

    try
    {
        fsm.process_event(some_event());
    }
    catch(...)
    {
        cout<<"Exception caught"<<endl;
    }


    if(fsm.terminated())
    {
        cout<<"fsm2 is TERMINATED"<<endl;
    }
    else
    {
        cout<<"fsm2 is RUNNING"<<endl;
    }
    return 0;
}

Выход кода:

FSM::FSM()
State::State()
State::react( const some_event &)
State::react( const sc::exception_thrown &)
State::~State()
Exception caught
fsm2 is TERMINATED

Я хочу, чтобы он выводил:

FSM::FSM()
State::State()
State::react( const some_event &)
State::react( const sc::exception_thrown &)
State::~State()
Exception caught
fsm2 is RUNNING
Теги:
boost-statechart

1 ответ

0

Вы должны предоставить собственный обработчик исключений на свой конечный автомат. См. Документацию по ускорению: http://www.boost.org/doc/libs/1_55_0/libs/statechart/doc/tutorial.html#ExceptionHandling

Невозможно, чтобы конечный автомат знал, находится ли он в правильном состоянии, когда возникает исключение, поэтому действие дескриптора исключения по умолчанию заключается в завершении sm. Ваш пользовательский обработчик может выполнить очистку/проверку, чтобы убедиться, что sm находится в правильном состоянии и распространяет информацию вверх в другой усадьбе.

Лично я никогда не видел веских оснований распространять информацию из SM за исключением. Вероятно, это возможно потому, что я никогда не работал в вашем конкретном домене, но тем не менее здесь я был рациональным:

Если событие не имеет значения, то проигнорируйте его или запишите его, это же событие может иметь значение в другом состоянии, а не в текущем. Если событие недействительно, т.е. Никогда не может произойти или имеет неправильное состояние, то это либо:

  • проблема с вашим кодом, и вы должны немедленно и немедленно решить проблему
  • проблема с недопустимым вводом из-за модуля, содержащего SM (аппаратное обеспечение размещено 3 отключенных события подряд, это никогда не может быть и т.д.). В этом случае вы не сможете обработать исключение должным образом в локальном модуле любым способом, и самое лучшее, что нужно сделать, это зарегистрировать проблему и переключиться в CatastrophicErrorState или что-то, что может быть оставлено только с помощью EvReset или что-то еще.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню