Boost Meta 状态机无限循环段故障
Boost Meta State Machine Infinite Loop Seg Fault
我正在尝试使用 Boost 状态机,但是当我的机器 运行 进入无限循环时我遇到了分段错误。本质上,我在如下所示的升压状态机函子示例中有相同的示例:
唯一的区别是我现在一进入 State4 就会触发 "event1",从而创建一个循环。这适用于数千次迭代,但随后会出现段错误。我是否违反了某种 UML 规则并溢出了堆栈?我基本上只有一个阻塞事件,然后我希望所有其他状态自动触发,然后以 State4 结束(例如,这实际上是等待来自网络的消息的阻塞调用)。我如何使用 Meta State Machine 正确地实现它,这样我就不会炸毁堆栈?
更新
我在这里包含了导致我的问题的源代码:
http://pastebin.com/fu6rzF0Q
这基本上是仿函数前端中的示例,但有以下更改:
新增"pretend"拦截来电功能:
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;
}
};
而且我还更新了转换中的最后一行table:
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 行的堆栈跟踪。
我还应该注意,无论我等待多长时间,我总是最终会出现段错误。我一直在尝试将睡眠时间更改为 1 - 100,它最终会死掉。我想我需要一些方法来在单个循环完成后展开堆栈。
更新 2
所以我发现当我在无限循环中触发事件时,我不会出现段错误。这是我所做的:
首先,我将转换 table 设置回原始示例:
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
最终我的目标是实现如下图所示的东西:
我的意图是让状态机启动,然后它将只等待传入消息而无需任何进一步干预。
我得出的结论是,如果您在任何 actions/guards/entry/exit 语句中调用 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());
}
}
我正在尝试使用 Boost 状态机,但是当我的机器 运行 进入无限循环时我遇到了分段错误。本质上,我在如下所示的升压状态机函子示例中有相同的示例:
唯一的区别是我现在一进入 State4 就会触发 "event1",从而创建一个循环。这适用于数千次迭代,但随后会出现段错误。我是否违反了某种 UML 规则并溢出了堆栈?我基本上只有一个阻塞事件,然后我希望所有其他状态自动触发,然后以 State4 结束(例如,这实际上是等待来自网络的消息的阻塞调用)。我如何使用 Meta State Machine 正确地实现它,这样我就不会炸毁堆栈?
更新
我在这里包含了导致我的问题的源代码:
http://pastebin.com/fu6rzF0Q
这基本上是仿函数前端中的示例,但有以下更改:
新增"pretend"拦截来电功能:
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;
}
};
而且我还更新了转换中的最后一行table:
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 行的堆栈跟踪。
我还应该注意,无论我等待多长时间,我总是最终会出现段错误。我一直在尝试将睡眠时间更改为 1 - 100,它最终会死掉。我想我需要一些方法来在单个循环完成后展开堆栈。
更新 2 所以我发现当我在无限循环中触发事件时,我不会出现段错误。这是我所做的:
首先,我将转换 table 设置回原始示例:
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
最终我的目标是实现如下图所示的东西:
我的意图是让状态机启动,然后它将只等待传入消息而无需任何进一步干预。
我得出的结论是,如果您在任何 actions/guards/entry/exit 语句中调用 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());
}
}