Linux编程之有限状态机FSM的理解与实现

 有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。

那有限状态机通常在什么地方被用到?

处理程序语言或者自然语言的 tokenizer,自底向上解析语法的parser,
各种通信协议发送方和接受方传递数据对消息处理,游戏AI等都有应用场景。

状态机有以下几种实现方法,我将一一阐述它们的优缺点。

一、使用if/else if语句实现的FSM

使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。

看看下面的例子,我们使用了大量的if/else if语句实现了一个简单的状态机,做到了根据状态的不同执行相应的操作,并且实现了状态的跳转。

 //比如我们定义了小明一天的状态如下 enum {     GET_UP,     GO_TO_SCHOOL,     HAVE_LUNCH,     GO_HOME,     DO_HOMEWORK,     SLEEP, };   int main() {     int state = GET_UP;     //小明的一天     while (1)     {         if (state == GET_UP)         {             GetUp(); //具体调用的函数             state = GO_TO_SCHOOL;  //状态的转移         }         else if (state == GO_TO_SCHOOL)         {             Go2School();             state = HAVE_LUNCH;         }         else if (state == HAVE_LUNCH)         {             HaveLunch();         }         ...         else if (state == SLEEP)         {             Go2Bed();             state = GET_UP;         }     }      return 0; } 

看完上面的例子,大家有什么感受?是不是感觉程序虽然简单易懂,但是使用了大量的if判断语句,使得代码很低端,同时代码膨胀的比较厉害。这个状态机的状态仅有几个,代码膨胀并不明显,但是如果我们需要处理的状态有数十个的话,该状态机的代码就不好读了。

二、使用switch实现FSM

使用switch语句实现的FSM的结构变得更为清晰了,其缺点也是明显的:这种设计方法虽然简单,通过一大堆判断来处理,适合小规模的状态切换流程,但如果规模扩大难以扩展和维护。

int main() {     int state = GET_UP;     //小明的一天     while (1)     {          switch(state)         {         case GET_UP:             GetUp(); //具体调用的函数             state = GO_TO_SCHOOL;  //状态的转移             break;         case GO_TO_SCHOOL:             Go2School();             state = HAVE_LUNCH;             break;         case HAVE_LUNCH:             HaveLunch();             state = GO_HOME;             break;             ...         default:             break;         }     }      return 0; } 

三、使用函数指针实现FSM

使用函数指针实现FSM的思路:建立相应的状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换。

当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。

下面给出一个使用函数指针实现的FSM的框架:

我们还是以“小明的一天”为例设计出该FSM。

先给出该FSM的状态转移图:

下面讲解关键部分代码实现

首先我们定义出小明一天的活动状态

//比如我们定义了小明一天的状态如下 enum {     GET_UP,     GO_TO_SCHOOL,     HAVE_LUNCH,     DO_HOMEWORK,     SLEEP, };

我们也定义出会发生的事件

enum {     EVENT1 = 1,     EVENT2,     EVENT3, };

定义状态表的数据结构

typedef struct FsmTable_s {     int event;   //事件     int CurState;  //当前状态     void (*eventActFun)();  //函数指针     int NextState;  //下一个状态 }FsmTable_t;

接下来定义出最重要FSM的状态表,我们整个FSM就是根据这个定义好的表来运转的。


                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信