我在具有极少(3)个状态的实时系统中有一个状态机.
typedef enum {
STATE1,
STATE2,
STATE3
} state_t;
Run Code Online (Sandbox Code Playgroud)
但是,这些状态之间的转换需要相当长的时间并且有自己的细分.所以我有两个选择,要么扩展主状态机,以便表示所有中间状态:
typedef enum {
STATE1,
STATE1_PREPARE_TRANSITION_TO_STATE2,
STATE1_DO_TRANSITION_TO_STATE2,
STATE1_PREPARE_TRANSITION_TO_STATE3,
STATE1_DO_TRANSITION_TO_STATE3,
STATE2,
...
} state_t;
Run Code Online (Sandbox Code Playgroud)
或者我为相关的主要状态创建一个嵌套的状态机:
typedef enum {
STATE1_NOT_ACTIVE,
STATE1_NORMAL,
STATE1_PREPARE_TRANSITION_TO_STATE2,
STATE1_DO_TRANSITION_TO_STATE2,
STATE1_PREPARE_TRANSITION_TO_STATE3,
STATE1_DO_TRANSITION_TO_STATE3
} sub_state1_t;
...
Run Code Online (Sandbox Code Playgroud)
两种可能性都有其优点和缺点.大型的状态机很容易变得混乱和复杂.但是,在第二种情况下使所有状态保持一致并不是微不足道的,并且许多函数需要有关全局状态和子状态的信息.
我想避免复杂的代码,它必须处理几个并行状态,如:
if ((global_state == STATE1) &&
(sub_state_1 == STATE1_DO_TRANSITION_TO_STATE2))
{
...
if (transition_xy_done(...))
{
global_state = STATE2;
sub_state_1 = STATE1_NOT_ACTIVE;
sub_state_2 = STATE2_NORMAL;
}
}
Run Code Online (Sandbox Code Playgroud)
这个问题的一般最佳方法是什么:许多小型和嵌套的状态机(有许多无效组合),一个大型状态机或其他任何东西?
许多小型状态机将为您提供更多的代码灵活性,特别是如果您需要重新设计任何东西.然后你应该(希望)能够更改嵌套状态机而无需更改任何其他嵌套状态机.
拥有更大的转换表不应该导致更长的查找,因为我假设您在内存中合理地布置表.如果有的话,你实际上应该能够从大机器中获得更高的速度,因为你没有额外的一两步,小型状态机可以在它们之间干净地过渡.但是考虑到这种方法增加的复杂性,我建议如下:使用嵌套状态机进行设计,然后一切正常后,如果需要,可以重构为单个状态机以获得一点速度提升.
首先,我想赞扬您认识到正在发生的事情并使这些状态变得明确(因为它们实际上是模型中的附加状态,而不是真正通过操作进行转换)。我经常看到状态机最终像你最后一个例子一样(你想避免)。当您在事件处理程序中测试“附加”状态变量时,这表明您的状态机具有更多已真正放入设计中的状态 - 这些显示会反映在设计中,而不是塞入现有状态的事件中带有一堆意大利面条编码的处理程序检查全局变量中编码的附加“状态”。
有几个 C++ 框架可以模拟分层状态机 - HSM -(这就是您的嵌套状态机想法听起来的样子),但我知道唯一支持直接 C 的框架是Quantum Framework,我认为购买这可能意味着相当程度的承诺(即,这可能不是一个简单的改变)。然而,如果您想研究这种可能性,Samek 已经写了很多关于如何用 C 支持 HSM 的文章(和一本书)。
但是,如果您不需要 HSM 模型的一些更复杂的部分(例如,不由“最内部”状态处理的事件会冒泡,以便可能由父状态处理),则完全支持进入和退出整个状态层次结构),那么就很容易支持嵌套状态机,就像完全独立的状态机一样,在进入/退出父状态时恰好启动和停止。
大状态机模型可能更容易实现一些(它只是现有框架中的几个状态)。我建议,如果将状态添加到当前状态机模式不会使模型变得太复杂,那么就这样做。
换句话说,让最适合您的模型的因素驱动您如何在软件中实现状态机。