有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型。可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。
状态机实现的方式有多种,下面讲述三种.
1. 使用if/else语句实现的FSM
使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。
看看下面的例子:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
enum YEAR_STATE
{
SPRING,
SUMMER,
AUTUMN,
WINTER
};
static void SpringThing()
{
printf("hello spring\n");
}
static void SummerThing()
{
printf("hello summer\n");
}
static void AutumnThing()
{
printf("hello autumn\n");
}
static void WinterThing()
{
printf("hello winter\n");
}
int main()
{
enum YEAR_STATE state = SPRING;
while (1) {
if (state == SPRING) {
SpringThing(); // 相应的处理
state = SUMMER; // 状态改变
} else if (state == SUMMER) {
SummerThing();
state = AUTUMN;
} else if (state == AUTUMN) {
AutumnThing();
state = WINTER;
} else if (state == WINTER) {
WinterThing();
state = SPRING;
}
sleep(1);
}
return 0;
}
简单易懂,这里实现了四季的更替,因为只有四种状态,所以逻辑清楚,试想如果有个几十种状态,我们的if else将会变得十分之长,维护起来很麻烦,删减和添加状态变得不方便,但是通过这个例子我们认识到状态机的内涵。
如下图:

在状态1时,遇到一个事件,此刻发生状态转换,一般在状态转换前,先要进行事件的处理,然后改变状态位,然后进入状态2,以此类推。
2. 使用switch case
这种做法和if else类似,结构上更清楚一些,代码如下:
int main()
{
enum YEAR_STATE state = SPRING;
while (1) {
switch (state) {
case SPRING:
SpringThing();
state = SUMMER;
break;
case SUMMER:
SummerThing();
state = AUTUMN;
break;
case AUTUMN:
AutumnThing();
state = WINTER;
break;
case WINTER:
WinterThing();
state = SPRING;
break;
default:
break;
}
sleep(1);
}
return 0;
}
3. 函数指针实现FSM,维护状态机表格
使用函数指针实现FSM的思路:建立状态机表,根据状态、事件定位相应的动作处理函数,执行完成后再进行状态的切换。
当然使用函数指针实现的FSM的过程还是比较费时费力,但是这一切都是值得的,因为当你的程序规模大时候,基于这种表结构的状态机,维护程序起来也是得心应手。
首先我们画出这个表

实现过程:
1.定义状态的枚举类型
typedef enum {
SPRING = 1,
SUMMER,
AUTUMN,
WINTER,
} YEAR_STATE;
2.定义事件的枚举类型
typedef enum {
EVENT1 = 1,
EVENT2,
EVENT3,
EVENT4,
} YEAR_EVENT;
3.定义状态表的数据类型
typedef struct {
YEAR_EVENT event; // 事件
YEAR_STATE curState; // 当前状态
void (*eventActFun)(); // 执行的动作
YEAR_STATE nextState; // 下一个状态
} FsmTable;
4.定义处理函数和建立状态表
static void SprintThing()
{
printf("this is spring\n");
}
static void SummerThing()
{
printf("this is summer\n");
}
static void AutumnThing()
{
printf("this is autumn\n");
}
static void WinterThing()
{
printf("this is winter\n");
}
static FsmTable g_yeadSwitchTable[] = {
/* 到来的事件,当前的状态,将要要执行的函数,下一个状态 */
{ EVENT1, SPRING, SummerThing, SUMMER },
{ EVENT2, SUMMER, AutumnThing, AUTUMN },
{ EVENT3, AUTUMN, WinterThing, WINTER },
{ EVENT4, WINTER, SprintThing, SPRING },
};
5.状态机工作运转
/* 具体状态机工作实现状态切换的数据类型 */
typedef struct {
YEAR_STATE curState; // 当前状态
FsmTable *table; // 状态表
uint32_t tableSize; // 表的项数
} FsmWork;
/* 事件处理 */
static void FsmEventProcess(FsmWork *fsm, YEAR_EVENT event)
{
uint32_t i = 0;
for (; i < fsm->tableSize; i++) {
/* 当且仅当当前状态下来了指定的事件,我才执行它 */
if ((event == fsm->table[i].event) &&
(fsm->curState == fsm->table[i].curState)) {
fsm->table[i].eventActFun();
/* 然后修改当前状态为匹配到项的指定下一个状态 */
fsm->curState = fsm->table[i].nextState;
break;
}
}
if (i >= fsm->tableSize) {
printf("there is no match\n");
}
return;
}
测试程序代码为:
/* state.c */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
typedef enum {
SPRING = 1,
SUMMER,
AUTUMN,
WINTER,
} YEAR_STATE;
typedef enum {
EVENT1 = 1,
EVENT2,
EVENT3,
EVENT4,
} YEAR_EVENT;
typedef struct {
YEAR_EVENT event; // 事件
YEAR_STATE curState; // 当前状态
void (*eventActFun)(); // 执行的动作
YEAR_STATE nextState; // 下一个状态
} FsmTable;
static void SprintThing()
{
printf("this is spring\n");
}
static void SummerThing()
{
printf("this is summer\n");
}
static void AutumnThing()
{
printf("this is autumn\n");
}
static void WinterThing()
{
printf("this is winter\n");
}
static FsmTable g_yeadSwitchTable[] = {
/* 到来的事件,当前的状态,将要要执行的函数,下一个状态 */
{ EVENT1, SPRING, SummerThing, SUMMER },
{ EVENT2, SUMMER, AutumnThing, AUTUMN },
{ EVENT3, AUTUMN, WinterThing, WINTER },
{ EVENT4, WINTER, SprintThing, SPRING },
};
/* 具体状态机工作实现状态切换的数据类型 */
typedef struct {
YEAR_STATE curState; // 当前状态
FsmTable *table; // 状态表
uint32_t tableSize; // 表的项数
} FsmWork;
/* 事件处理 */
static void FsmEventProcess(FsmWork *fsm, YEAR_EVENT event)
{
uint32_t i = 0;
for (; i < fsm->tableSize; i++) {
/* 当且仅当当前状态下来了指定的事件,我才执行它 */
if ((event == fsm->table[i].event) &&
(fsm->curState == fsm->table[i].curState)) {
fsm->table[i].eventActFun();
/* 然后修改当前状态为匹配到项的指定下一个状态 */
fsm->curState = fsm->table[i].nextState;
break;
}
}
if (i >= fsm->tableSize) {
printf("there is no match\n");
}
return;
}
int main()
{
FsmWork myWorkfsm = {
.curState = SPRING,
.table = g_yeadSwitchTable,
.tableSize = sizeof(g_yeadSwitchTable) / sizeof(g_yeadSwitchTable[0])
};
printf("\n-------1--init spring------\n");
printf("state:%d\n", myWorkfsm.curState);
printf("\n-------2--spring->summer------\n");
FsmEventProcess(&myWorkfsm, EVENT1);
printf("state:%d\n", myWorkfsm.curState);
printf("\n-------3--summer->autumn------\n");
FsmEventProcess(&myWorkfsm, EVENT2);
printf("state:%d\n", myWorkfsm.curState);
printf("\n-------4--autumn->winter------\n");
FsmEventProcess(&myWorkfsm, EVENT3);
printf("state:%d\n", myWorkfsm.curState);
printf("\n-------5--winter->spring------\n");
FsmEventProcess(&myWorkfsm, EVENT4);
printf("state:%d\n", myWorkfsm.curState);
printf("\n-------6--receive EVENT2 not EVENT1------\n");
FsmEventProcess(&myWorkfsm, EVENT2);
printf("state:%d\n", myWorkfsm.curState);
return 0;
}
结果为:
-------1--init spring------
state:1
-------2--spring->summer------
this is summer
state:2
-------3--summer->autumn------
this is autumn
state:3
-------4--autumn->winter------
this is winter
state:4
-------5--winter->spring------
this is spring
state:1
-------6--receive EVENT2 not EVENT1------
there is no match
state:1