Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 大型与嵌套状态机_C_State Machine - Fatal编程技术网

C 大型与嵌套状态机

C 大型与嵌套状态机,c,state-machine,C,State Machine,我在实时系统中有一个状态机,只有很少(3)个状态 然而,这些状态之间的转换需要相当长的时间,并且有自己的细分。所以我有两个选择,要么扩展主状态机,以表示所有中间状态: typedef enum { STATE1, STATE1_PREPARE_TRANSITION_TO_STATE2, STATE1_DO_TRANSITION_TO_STATE2, STATE1_PREPARE_TRANSITION_TO_STATE3, STATE1_DO_TRANSIT

我在实时系统中有一个状态机,只有很少(3)个状态

然而,这些状态之间的转换需要相当长的时间,并且有自己的细分。所以我有两个选择,要么扩展主状态机,以表示所有中间状态:

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;
    }
}

对于这样的问题,通常最好的解决方法是什么:许多小型嵌套状态机(具有许多无效的组合)、一个大型状态机或其他任何东西?

正如您所提到的,大型状态机变得混乱,因此很难维护。一些较小的短信总是更容易理解和维护


大SM的另一个缺点是转换表更大,因此查找需要更长的时间。

许多小型状态机将为您提供更大的代码灵活性,特别是当您需要重新设计任何东西时。然后,您应该(希望)能够在不必更改任何其他嵌套状态机的情况下更改嵌套状态机


拥有更大的转换表不会导致更长的查找时间,因为我假设您在内存中合理地布局了表。如果有什么不同的话,您实际上应该能够从大机器中获得更快的速度,因为您没有小状态机在它们之间进行干净转换所需的额外一到两个步骤。但是考虑到这种方法的复杂性,我建议如下:使用嵌套状态机进行设计,然后一旦一切正常,如果需要,重构为单个状态机以获得一点速度提升。

为什么不使用?

首先,我要赞扬您认识到发生了什么,并使这些状态显式化(因为它们实际上是模型中的附加状态,而不是真正的动作转换)。当您在事件处理程序中对“其他”状态变量进行测试时,这表明您的状态机具有更多您真正投入到设计中的状态-这些状态将反映在设计中,而不是通过一系列意大利面编码的检查来干扰现有状态的事件处理程序,以检查全局va中编码的其他“状态”流氓

<>有几种C++模型可以用来构造层次状态机——HSMs -(这是你嵌套的状态机的想法听起来像什么),但是我知道的唯一一个支持直C的方法,我认为购买它可能意味着一个不错的承诺水平(也就是说,它可能不是简单的改变)。但是,如果您想研究这种可能性,Samek已经写了很多关于如何在C中支持HSMs的文章()

但是,如果您不需要HSM模型的某些更复杂的部分(例如,不由“最内部”状态处理的事件会冒泡,可能由父状态处理,则对整个状态层次结构的完全进入和退出支持),那么就很容易支持嵌套状态机,就像完全独立的状态机一样,当父状态进入/退出时,它们会启动和停止

大状态机模型可能更容易实现(它只是现有框架中的多个状态)。我建议,如果将状态添加到当前状态机模式不会使模型太复杂,那么就这样做吧


换句话说,让最适合您的模型的东西来驱动您如何在软件中实现状态机。

我认为没有一种单一的、通用的方法。正如其他人所说,这取决于您正在尝试做什么

广义地说,我会避免将小型状态机嵌套在大型状态机中,因为当您试图简化事情时,您不仅添加了更多的状态,因此也增加了复杂性,现在还需要跟踪两个状态变量

特别是,在遍历“外部”状态机中的状态时,必须正确初始化“内部”状态变量。例如,如果由于错误,外部状态机中存在无法重置内部状态机状态变量的转换,该怎么办

一个可能的例外是,所有内部状态机都执行相同的操作。如果可以对数据进行参数化(例如,通过使用数组),那么您可以使用内部状态机的单个实现,并且可以使用计数器或类似物替换外部状态机

举一个简单的例子:

#define MyDataSIZE 10

void UpdateStateMachine(void)
{
    static enum {BeginSTATE, DoStuffSTATE, EndSTATE} State = BeginSTATE;
    static unsigned int Counter = 0;
    static unsigned int MyData[MyDataSIZE];

    switch(State)
    {
        default:
        case BeginSTATE:
            /* Some code */
            if(/* Some condition*/)
                {State = DoStuffSTATE;}
            break;
        case DoStuffSTATE:
            /* Some actions on MyData[Counter] */
            if(/* Some condition*/)
                {State = EndSTATE;}
            break;
        case EndSTATE:
            /* Some code */
            if(/* Some condition*/)
            {
                Counter++;
                if(Counter >= MyDataSIZE)
                    {Counter = 0;}
                State = BeginSTATE;
            } /* if */
            break;
    } /* switch */
} /* UpdateStateMachine() */

我投票支持更大的状态机,假设一台机器只能处于一个大的状态机状态,它在逻辑上应该存在

通过使用一台大型计算机,您可以利用环境的特性来防止同时存在两种状态的状态,从而使程序更安全、更可读

另外,一个大型状态机的优点是,任何其他程序员都可以通过查看一个地方(即了解全局)轻松理解所有状态,而不是只查看一个地方,希望了解子分区,然后必须查看每个子分区

正如您所建议的,使用多个状态机将迫使您发送更多参数,对每个状态执行多个测试,等等


至于未来的预期,我相信。

您是否考虑过使用某种状态机生成器?是否有任何生成器工具可以决定是一个大的还是七个
#define MyDataSIZE 10

void UpdateStateMachine(void)
{
    static enum {BeginSTATE, DoStuffSTATE, EndSTATE} State = BeginSTATE;
    static unsigned int Counter = 0;
    static unsigned int MyData[MyDataSIZE];

    switch(State)
    {
        default:
        case BeginSTATE:
            /* Some code */
            if(/* Some condition*/)
                {State = DoStuffSTATE;}
            break;
        case DoStuffSTATE:
            /* Some actions on MyData[Counter] */
            if(/* Some condition*/)
                {State = EndSTATE;}
            break;
        case EndSTATE:
            /* Some code */
            if(/* Some condition*/)
            {
                Counter++;
                if(Counter >= MyDataSIZE)
                    {Counter = 0;}
                State = BeginSTATE;
            } /* if */
            break;
    } /* switch */
} /* UpdateStateMachine() */