0

我想实现一个状态机,它会定期监控一些状态数据(我系统的状态)并对其做出反应。

对于状态机来说,这似乎是非常基本的事情(我以前曾多次遇到过这个问题),但我找不到一个好的方法来做到这一点。这是一些伪代码来解释我想要实现的目标:

// some data that is updated from IOs for example
MyData data;

int state = 0;

while( true ) {
    update( & data ); //read a packet from serial port 
                      //and update the data structure
    switch( state ) {
    case 0:
        if( data.field1==0 ) state = 1;
        else doSomething();
        break;
    case 1:
        if( data.field2>0 ) state = 2;
        else doSomethingElse();
        break;

    // etc.

    }
    usleep(100000); //100ms
}

当然最重要的是,我希望能够在进入和退出状态时执行一些操作,也许在状态的每次迭代中执行一些操作,有子状态、历史等。这就是为什么这种简单的方法很快变得不切实际的原因,因此提升状态图。

我已经考虑了一些解决方案,我想得到一些反馈。

1)我可以列出我所有的转换条件并为每个条件创建一个事件。然后我会有一个循环来监控每个布尔切换的时间。例如,对于我的第一个条件,它可能是:

if( old_data.field1!=0 && new_data.field1==0 )
    // post an event of type Event 1

但似乎很快就会变得困难

2) 有一个所有状态都响应的事件。只要有一些新的状态数据可用,就会发布此事件。结果,当前状态将检查数据并决定是否启动到另一个状态的转换

3) 让所有状态都继承自定义 do_work(const MyData & data) 方法的接口,该方法将在循环中从外部调用,检查数据并决定是否启动到另一个状态的转换

另外,我愿意使用另一个框架(即 Macho 或 boost MSM)

4

1 回答 1

1

与 boost MSM、状态图和 QP 合作后,我认为您在状态图方面走在了正确的轨道上。MSM 速度更快,但如果您对状态机或元编程没有太多经验,那么如果您做错了什么,来自 MSM 的错误消息将很难理解。boost.statecharts 是最简洁、最容易理解的。至于 QP,它以嵌入式风格编写(大量预处理器的东西,较弱的静态检查),尽管它也适用于 PC 环境。我也相信它更慢。它确实具有在许多小型 ARM 和类似处理器上工作的优势。与提升解决方案相比,它不是免费用于商业用途的。

为每种类型的状态更改创建事件不会扩展。我会让一种类型的事件EvStateChanged给它一个数据成员,其中包含对数据集的副本或引用(如果你需要的话,可能还有一个旧数据)。然后,您可以使用服装反应来处理您在任何状态上下文中需要的任何内容。尽管默认转换在烤箱环境(通常用于演示 SM 功能)中运行良好,但我见过的大多数现实世界的 SM 都有许多自定义反应,不要害羞地使用它们。

我不太了解您的问题,无法给出代码示例,但大致如下:

while( true ) {
    update( & data ); //read a packet from serial port 
                      //and update the data structure
    if(data != oldData){
          sm.process_event(EvDataChanged(data,oldData));
    }
    else{
        timeout++;
        if(timeout>MAX_TIMEOUT)
            sm.process_event(EvTimeout());
    }
    usleep(100000); //100ms
}

然后根据以下状态处理客户反应中的数据更改:

SomeState::~SomeState(){
    DoSomethingWhenLeaving();
}
sc::result SomeState::react( const EvDataChanged & e){
    if(e.oldData.Field1 != e.newData.Field1){
        DoSomething();
        return transit<OtherState>();
    }
    if(e.oldData.Field2 != e.newData.Field2){
        return transit<ErrorState>();   //is not allowed to change in this state
    }
    if(e.oldData.Field3 == 4){
        return forward_event();  //superstate should handle this
    }
    return discard_event(); //don't care about anything else in this context
}
于 2013-06-28T17:44:04.697 回答