如何防止boost :: statetechart因抛出异常而终止

时间:2014-02-20 09:47:36

标签: c++ boost-statechart

我已经实现了一个继承boost :: statechart的状态机。当我调用fsm.process_event( some_event() )期望哪个反应会抛出异常时,事实证明在使用try-catch块处理异常后,我的状态机实例fsm被终止。也就是说,fsm.terminated()会返回true。在某些情况下,我不希望它被终止。就像我希望statemachine抛出异常以通知调用者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

我希望它输出:

{{1}}

1 个答案:

答案 0 :(得分:0)

您应该为状态机提供自定义异常处理程序。请参阅此处的提升文档:http://www.boost.org/doc/libs/1_55_0/libs/statechart/doc/tutorial.html#ExceptionHandling

当抛出异常时,状态机无法知道它是否仍处于有效状态,这就是异常句柄的默认操作是终止sm的原因。您的自定义处理程序可以执行清理/检查以确保sm处于有效状态,并以不同的方式向上传播信息。

就我个人而言,我从未见过有充分理由通过例外将信息传播出SM。这可能很可能是因为我从未在你的特定领域工作,但这里的理由是:

如果事件无关紧要,则忽略它或记录它,同一事件可能与另一个状态相关,而不是当前状态。如果事件无效,即可能永远不会发生或状态不正确,则可以是:

  • 您的代码存在问题,您应该立即断言并处理问题
  • 来自包含SM的模块之外的无效输入的问题(硬件连续发布3个断开连接的事件,这可能永远不会等等)。在这种情况下,您无法以任何方式在本地模块中正确处理异常,最好的办法是记录问题并切换到CatastrophicErrorState或者只能留下EvReset的东西。