提升Meta状态机无限循环段故障

时间:2016-10-22 01:43:00

标签: c++11 boost uml state-machine boost-msm

我正在尝试使用Boost状态机,但是在无限循环中运行我的机器时遇到了分段错误。基本上我在下面显示的boost状态机仿函数示例中有相同的示例:

enter image description here

唯一的区别是我现在只要输入State4就会触发“event1”,从而创建一个循环。这适用于几千次迭代,但随后会出现故障。我是否打破了某种UML规则并溢出了堆栈?我基本上只有一个阻塞事件,然后我希望所有其他状态自动触发,然后最终进入State4(实际上这将是一个阻塞调用,等待来自网络的消息)。我如何使用Meta State Machine正确实现这一点,所以我不会炸毁堆栈?

更新
我在这里包含了导致我问题的源代码: http://pastebin.com/fu6rzF0Q

这基本上是仿函数前端的示例,除了以下更改:

添加了“假装”阻止呼叫功能:

  struct BlockingCall {
    template <class EVT, class FSM, class SourceState, class TargetState>
    void operator()(EVT const &, FSM &, SourceState &, TargetState &) {
      std::cout << "my_machine::Waiting for a thing to happen..." << std::endl;
      // Pretend I'm actually waiting for something
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      std::cout << "my_machine::OMG the the thing happened!" << std::endl;
    }
  };

我还更新了转换表中的最后一行:

        struct transition_table : mpl::vector<
        //    Start     Event         Next      Action               Guard
        //  +---------+-------------+---------+---------------------+----------------------+
        Row < State1  , none        , State2                                               >,
        Row < State2  , none        , State3  , State2ToState3                             >,
        Row < State3  , none        , State4  , none                , always_false         >,
        //  +---------+-------------+---------+---------------------+----------------------+
        Row < State3  , none        , State4  , State3ToState4      , always_true          >,
        Row < State4  , none        , State1  , BlockingCall                               >
        //  +---------+-------------+---------+---------------------+----------------------+
    > {};

请注意,不再需要触发从State4移动到State1的事件。毫无疑问,这段代码会给你一个seg错误,并且堆栈跟踪的长度为1000行。

我还应该注意,无论我等待的时间,我总是最终出错。我已经玩过将睡眠改为1 - 100,最终会死亡。我想我需要一些方法在单个循环完成后展开堆栈。

更新2 所以当我在无限循环中触发事件时,我发现我不会出错。这是我做的:

首先,我将转换表设置回原始示例:

struct transition_table : mpl::vector<
        //    Start     Event         Next      Action               Guard
        //  +---------+-------------+---------+---------------------+----------------------+
        Row < State1  , none        , State2                                               >,
        Row < State2  , none        , State3  , State2ToState3                             >,
        Row < State3  , none        , State4  , none                , always_false         >,
        //  +---------+-------------+---------+---------------------+----------------------+
        Row < State3  , none        , State4  , State3ToState4      , always_true          >,
        Row < State4  , event1      , State1  , none                                       >
        //  +---------+-------------+---------+---------------------+----------------------+
    > {};

然后我将主程序更改为以下内容:

void test() {
  my_machine p;

  // needed to start the highest-level SM. This will call on_entry and mark the
  // start of the SM
  // in this case it will also immediately trigger all anonymous transitions
  p.start();
  // this event will bring us back to the initial state and thus, a new "loop"
  // will be started
  while (true) {
    p.process_event(event1());
  }
}

现在我一直在全速奔跑(没有睡觉)而且我没有出现故障。基于此,似乎没有办法启动状态机并让它运行和处理内部事件,这是正确的吗?我总是必须在外面有一些至少触发的过程吗?

更新3 最终我的目标是实现如下图:

我的目的是让状态机启动,然后只需等待传入的消息而不需要任何进一步的干预。

1 个答案:

答案 0 :(得分:0)

我得出的结论是,如果在任何actions / guards / entry / exit语句中调用FILE *,则根本无法使状态机具有内部循环。我相信问题在于,每次进行该调用时,都会在堆栈上推送更多信息,直到最终溢出堆栈为止。如果您有匿名转换在状态机中创建无限循环,也是如此。所以我的结论是你必须至少有 ONE 外部事件来触发循环。因此,以下代码是我迄今为止找到的最佳解决方案:

fsm.process_event(e1)