我在实时系统中有一个状态机,只有很少的(3)个状态。
typedef enum {
STATE1,
STATE2,
STATE3
} state_t;然而,这些状态之间的转换需要相当长的时间,并且有自己的细分。因此,我有两个选择,要么扩展主状态机,以便表示所有中间状态:
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;或者我为相关的主状态创建一个嵌套的状态机:
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;
...这两种可能性都有其优点和缺点。大型状态机很容易变得混乱和复杂。然而,在第二种情况下,让所有状态保持一致也不是微不足道的,许多函数都需要关于全局状态和子状态的信息。
我希望避免必须处理多个并行状态的复杂代码,例如:
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;
}
}解决此类问题的最佳方法通常是什么:多个小的嵌套状态机(具有许多无效组合),一个大的状态机或其他任何东西?
发布于 2009-09-10 21:11:23
首先,我要赞扬您认识到正在发生的事情,并使这些状态变得明确(因为它们实际上是模型中的附加状态,而不是真正的带有动作的转换)。我经常看到状态机像您的上一个示例一样结束(您希望避免)。当你在事件处理程序中测试“附加”状态变量时,这是一个迹象,表明你的状态机有更多你真正放在设计中的状态--这些状态会反映在设计中,而不是被塞进现有状态的事件处理程序中,用一堆意大利面条编码的检查来检查在全局变量中编码的附加“状态”。
有几个C++框架可以建模分层状态机- HSMs (这就是你的嵌套状态机想法听起来是什么样子),但我所知道的唯一一个直接支持C语言的框架是Quantum Framework,我认为购买它可能意味着一个像样的承诺级别(即,这可能不是一个简单的改变)。但是,如果您想研究这种可能性,Samek已经写了很多关于如何用C语言支持HSM的文章(and a book)。
然而,如果你不需要HSM模型的一些更复杂的部分(例如,“最里面”状态不能处理的事件,可能由父状态处理,对整个状态层次结构的完全进入和退出支持),那么很容易支持嵌套状态机,就像完全独立的状态机一样,当进入/退出父状态时,恰好启动和停止。
大状态机模型可能更容易实现(它只是您现有框架中的几个状态)。我建议,如果将状态添加到当前的状态机模式不会使模型太复杂,那么就使用它。
换句话说,让最适合你的模型驱动你如何在软件中实现状态机。
发布于 2009-09-10 10:55:22
许多小型状态机将为您提供更大的代码灵活性,特别是当您需要重新设计任何东西时。然后,您应该(希望)能够更改嵌套状态机,而不必更改任何其他嵌套状态机。
拥有更大的转换表应该不会导致更长的查找时间,因为我假设您在内存中合理地布局了该表。如果有什么不同的话,您实际上应该能够从大型机器中获得更快的速度,因为您没有使用小型状态机在它们之间干净地转换所需的额外的一两个步骤。但考虑到这种方法的复杂性,我建议如下:使用嵌套状态机进行设计,一旦一切正常,如果需要的话,重构到单个状态机中,以获得一些速度提升。
发布于 2009-09-10 10:46:37
正如你所提到的,大型状态机变得杂乱无章,因此很难维护。几个较小的SMs总是更容易理解和维护。
大SM的另一个缺点-更大的转换表,因此查找时间更长。
https://stackoverflow.com/questions/1404526
复制相似问题