状态机
理论上分为有限状态机和无限状态机,但无限状态机的状态集Q是无限的,这蕴含着转移函数有无限多的映射,因此它是一种思考理论上的模型。
状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:
现态:是指当前所处的状态。
条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
有限状态机FSM分为两大类
若输出只和状态有关而与输入无关,则称为Moore状态机
输出不仅和状态有关而且和输入有关系,则称为Mealy状态机
作为两年以上的程序老鸟,状态机的写法理应成熟简洁。但往往在快速完成的要求下总会选用标记位和switch、if-else快速构成状态机逻辑。俗话说磨刀不误砍柴工,地基决定上层建筑,花点时间把每一个知识点框架整理一遍,将来你的摩天大楼建造将会更快更稳。以下两个是一些典型的c语言状态机,写法不一样,但是蕴含的思维是大同小异的,第二个更符合大多数场合。
处理按键引发的多状态切换
转载自https://blog.csdn.net/qq_35579835/article/details/106536745
/***********************************************
1、定义状态接口,以MP3的状态接口为例,每种状态下都可能发生
两种按键动作。
************************************************/
typedef struct State{
void (* stop)();
void (* palyOrPause)();
}State;
/***********************************************
2、定义系统当前状态指针,保存系统的当前状态
************************************************/
State * pCurrentState;
/***********************************************
3、定义具体状态,根据状态迁移图来实现具体功能和状态切换。
************************************************/
void ignore();
void startPlay();
void stopPlay();
void pausePlay();
void resumePlay();
//空闲状态时,stop键操作无效,play/pause会开始播放音乐
State IDLE = {
ignore,
startPlay
};
//播放状态时,stop键会停止播放音乐,play/pause会暂停播放音乐
State PLAY = {
stopPlay,
pausePlay
};
//暂停状态时,stop键会停止播放音乐,play/pause会恢复播放音乐
State PAUSE = {
stopPlay,
resumePlay
};
void ignore()
{
//空函数,不进行操作
}
void startPlay()
{
//实现具体功能
printf("开始播放音乐
");
//进入播放状态
pCurrentState = &PLAY;
}
void stopPlay()
{
//实现具体功能
printf("停止播放音乐
");
//进入空闲状态
pCurrentState = &IDLE;
}
void pausePlay()
{
//实现具体功能
printf("暂停播放音乐
");
//进入暂停状态
pCurrentState = &PAUSE;
}
void resumePlay()
{
//实现具体功能
printf("恢复播放音乐
");
//进入播放状态
pCurrentState = &PLAY;
}
/***********************************************
4、定义主程序上下文操作接口,主程序只关心当前状态,不关心状态之间
是怎么变化的。
************************************************/
void onStop();
void onPlayOrPause();
State context = {
onStop,
onPlayOrPause
};
void onStop(State *pThis)
{
pCurrentState->stop(pThis);
}
void onPlayOrPause(State *pThis)
{
pCurrentState->palyOrPause(pThis);
}
/***********************************************
5、初始化系统当前状态指针,其实就是指定系统的起始状态
************************************************/
void init()
{
pCurrentState = &IDLE;
}
/***********************************************
6、主程序通过上下文操作接口来控制系统当前状态的变化
************************************************/
void main()
{
init();
context.palyOrPause();//播放
context.palyOrPause();//暂停
context.palyOrPause();//播放
context.stop();//停止
}
由于某个事件触发的状态切换
转载自https://www.jianshu.com/p/917c0fb8778b
/*1.定义状态数据的枚举类型*/
enum year_state
{
SPRING = 1,
SUMMER,
AUTUMN,
WINTER
};
/*2.定义事件的枚举类型*/
enum year_event
{
EVENT1 = 1,
EVENT2,
EVENT3,
EVENT4,
};
/*3.定义状态表的数据类型*/
typedef struct FsmTable_s
{
int event; //事件
int CurState; //当前状态
void (*eventActFun)(); //函数指针
int NextState; //下一个状态
}FsmTable_t;
/*4.定义处理函数及建立状态表*/
void spring_thing()
{
printf("this is spring
");
}
void summer_thing()
{
printf("this is summer
");
}
void autumn_thing()
{
printf("this is autumn
");
}
void winter_thing()
{
printf("this is winter
");
}
FsmTable_t year_table[] =
{
//{到来的事件,当前的状态,将要要执行的函数,下一个状态}
{ EVENT1, SPRING, summer_thing, SUMMER },
{ EVENT2, SUMMER, autumn_thing, AUTUMN },
{ EVENT3, AUTUMN, winter_thing, WINTER },
{ EVENT4, WINTER, spring_thing, SPRING },
//add your codes here
};
/*5.状态机类型,及状态机接口函数*/
/*状态机类型*/
typedef struct FSM_s{
int curState;//当前状态
FsmTable_t * pFsmTable;//状态表
int size;//表的项数
}FSM_t;
/*状态机注册,给它一个状态表*/
void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable)
{
pFsm->pFsmTable = pTable;
}
/*状态迁移*/
void FSM_StateTransfer(FSM_t* pFsm, int state)
{
pFsm->curState = state;
}
/*事件处理*/
void FSM_EventHandle(FSM_t* pFsm, int event)
{
FsmTable_t* pActTable = pFsm->pFsmTable;
void (*eventActFun)() = NULL; //函数指针初始化为空
int NextState;
int CurState = pFsm->curState;
int g_max_num = pFsm->size;
int flag = 0; //标识是否满足条件
int i;
/*获取当前动作函数*/
for (i = 0; i<g_max_num; i++)
{
//当且仅当当前状态下来个指定的事件,我才执行它
if (event == pActTable[i].event && CurState == pActTable[i].CurState)
{
flag = 1;
eventActFun = pActTable[i].eventActFun;
NextState = pActTable[i].NextState;
break;
}
}
if (flag) //如果满足条件了
{
/*动作执行*/
if (eventActFun)
{
eventActFun();
}
//跳转到下一个状态
FSM_StateTransfer(pFsm, NextState);
}
else
{
printf("there is no match
");
}
}
测试程序代码为
/*state.c*/
#include <stdio.h>
enum year_state{
SPRING = 1,
SUMMER,
AUTUMN,
WINTER
};
enum year_event{
EVENT1 = 1,
EVENT2,
EVENT3,
EVENT4,
};
typedef struct FsmTable_s{
int event; //事件
int CurState; //当前状态
void (*eventActFun)(); //函数指针
int NextState; //下一个状态
}FsmTable_t;
void spring_thing()
{
printf("this is spring
");
}
void summer_thing()
{
printf("this is summer
");
}
void autumn_thing()
{
printf("this is autumn
");
}
void winter_thing()
{
printf("this is winter
");
}
FsmTable_t year_table[] =
{
//{到来的事件,当前的状态,将要要执行的函数,下一个状态}
{ EVENT1, SPRING, summer_thing, SUMMER },
{ EVENT2, SUMMER, autumn_thing, AUTUMN },
{ EVENT3, AUTUMN, winter_thing, WINTER },
{ EVENT4, WINTER, spring_thing, SPRING },
//add your codes here
};
typedef struct FSM_s{
int curState;//当前状态
FsmTable_t * pFsmTable;//状态表
int size;//表的项数
}FSM_t;
/*状态机注册,给它一个状态表*/
void FSM_Regist(FSM_t* pFsm, FsmTable_t* pTable)
{
pFsm->pFsmTable = pTable;
}
/*状态迁移*/
void FSM_StateTransfer(FSM_t* pFsm, int state)
{
pFsm->curState = state;
}
/*事件处理*/
void FSM_EventHandle(FSM_t* pFsm, int event)
{
FsmTable_t* pActTable = pFsm->pFsmTable;
void (*eventActFun)() = NULL; //函数指针初始化为空
int NextState;
int CurState = pFsm->curState;
int g_max_num = pFsm->size;
int flag = 0; //标识是否满足条件
int i;
/*获取当前动作函数*/
for (i = 0; i<g_max_num; i++)
{
//当且仅当当前状态下来个指定的事件,我才执行它
if (event == pActTable[i].event && CurState == pActTable[i].CurState)
{
flag = 1;
eventActFun = pActTable[i].eventActFun;
NextState = pActTable[i].NextState;
break;
}
}
if (flag) //如果满足条件了
{
/*动作执行*/
if (eventActFun)
{
eventActFun();
}
//跳转到下一个状态
FSM_StateTransfer(pFsm, NextState);
}
else
{
printf("there is no match
");
}
}
int main()
{
FSM_t year_fsm;
FSM_Regist(&year_fsm,year_table);
year_fsm.curState = SPRING;
year_fsm.size = sizeof(year_table)/sizeof(FsmTable_t);
printf("
-------1--init spring------
");
printf("state:%d
",year_fsm.curState);
printf("
-------2--spring->summer------
");
FSM_EventHandle(&year_fsm,EVENT1);
printf("state:%d
",year_fsm.curState);
printf("
-------3--summer->autumn------
");
FSM_EventHandle(&year_fsm,EVENT2);
printf("state:%d
",year_fsm.curState);
printf("
-------4--autumn->winter------
");
FSM_EventHandle(&year_fsm,EVENT3);
printf("state:%d
",year_fsm.curState);
printf("
-------5--winter->spring------
");
FSM_EventHandle(&year_fsm,EVENT4);
printf("state:%d
",year_fsm.curState);
printf("
-------6--receive EVENT2 not EVENT1------
");
FSM_EventHandle(&year_fsm,EVENT2);
printf("state:%d
",year_fsm.curState);
return 0;
}
最新评论