【问题标题】:Boost Meta State Machine Infinite Loop Seg FaultBoost Meta State Machine Infinite Loop Seg Fault
【发布时间】:2016-10-22 01:42:59
【问题描述】:

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

唯一的区别是我现在一进入 State4 就触发“event1”发生,因此创建了一个循环。这适用于数千次迭代,但随后会出现段错误。我是否违反了某种 UML 规则并溢出了堆栈?我基本上只有一个阻塞事件,然后我希望所有其他状态自动触发,然后以 State4 结束(例如,这实际上是等待来自网络的消息的阻塞调用)。我将如何使用元状态机正确实现这一点,这样我就不会炸毁堆栈?

更新
我在这里包含了导致我的问题的源代码: 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 的事件。毫无疑问,这段代码会给你一个段错误,并且会有一个长达 1000 行的堆栈跟踪。

我还应该注意,无论我等待多长时间,我最终都会出现段错误。我已经尝试将 sleep 更改为 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 最终我的目标是实现如下图所示的东西:

我的意图是启动状态机,然后它会简单地等待传入消息而无需任何进一步的干预。

【问题讨论】:

  • 你应该发一个minimal reproducible example
  • @m.s.我已根据您的建议更新了我的问题。
  • 虽然我无法回答 Wesson 如何在特定工具中实现它,但我将仅限于评论。从 UML 的角度来看,没有任何价值认为 lip 必须是有限的。实际上,状态机通常是无限的,但是通常一个或多个状态被认为是最终的。然而,当您进行实际实现时,您可能会遇到许多问题,而无限循环往往会暴露这些问题。由于工具限制,绝对有效的 UML 状态机可能无法在您选择的工具中实现。
  • 感谢您的回复。我很高兴知道,至少我的状态图在技术上没有错误,但是有一个实现细节不允许我按照我最初的意图来表现它。

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


【解决方案1】:

我得出的结论是,如果您在任何操作/守卫/进入/退出语句中调用fsm.process_event(e1),根本没有办法让状态机具有内部循环。我认为问题在于每次进行调用时,都会将更多信息推送到堆栈上,直到最终溢出堆栈。如果您有匿名转换在状态机中创建无限循环,这也是如此。所以我的结论是你必须至少有 ONE 外部事件来触发循环。因此,以下代码是迄今为止我找到的最佳解决方案:

void test() {
  my_machine p;
  p.start();
  // Must have at least 1 triggering external event to not overflow the stack
  while (true) {
    p.process_event(event1());
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多