简体   繁体   中英

How to prevent boost::statetechart from terminating due to exception thrown

I have implemented a state machine that inherits boost::statechart. When I call fsm.process_event( some_event() ) which reaction is expected to throw exception it turns out that after I handle the exception with try-catch block my statemachine instance fsm is terminated. That is, fsm.terminated() returns true . In some cases I don't want it to get terminated. Like when I want the statemachine to throw exception to inform the caller of fsm.process_event( irrelevant_event() ) for non-handled event and to keep its current prior to the event state.

In short - how can I prevent boost::statechart from terminating after it throws an exception and keep its prior to the exception state?

Example Code:

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;
}

Code Output:

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

I want it to Output:

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

You should provide a custom exception handler to your state machine. See the boost documentation here: http://www.boost.org/doc/libs/1_55_0/libs/statechart/doc/tutorial.html#ExceptionHandling

It is impossible for the state machine to know if it is still in a valid state when an exception is thrown which is why the default action of the exception handle is to terminate the sm. Your custom handler can do clean up/checking to make sure the sm is in a valid state and propagate the information upwards in a different manor.

Personally I have never seen good reason to propagate information out of a SM by exception. This may in all likelihood be because I have never worked in your specific domain but none the less here is my rational:

If the event is irrelevant then ignore it or log it, this same event could be relevant in another state just not the current one. If the event is invalid, ie could never happen or has incorrect state then this is either:

  • a problem with your code and you should assert and deal with the problem immediately
  • a problem with invalid input from beyond the module containing the SM (the hardware posted 3 disconnected events in succession, this could never be etc.). In this case you cannot handle the exception properly in the local module any way and the best thing to do is log the problem and switch into a CatastrophicErrorState or something that can only be left with a EvReset or something.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM