FSM有限状态机其二
我们在上篇博客中简单探索了一下表函数法实现的FSM,我们通过函数指针跟结构体的配合来消除了巨大的 switch(current_state),每个状态独立成函数,易于扩展。状态处理函数 = δ 函数的分段实现。 state_table[s](fsm, e) 执行 δ(s, e)。
局限:
没有“动作”的概念。转移时无法自动执行硬件初始化/清理。
没有“层次”。多个状态共享行为时,代码重复。
我们在这篇博客中,我们要给它实现”动作”这个概念
1 | struct StateMachine { |
观察我们全新的StateMachine结构体的声明,可以发现它的内部多了两个新的成员,这两个成员其实也是指针数组。存储的数据类型为void ()(void)
顺便一提,C语言有时候这个语法真的是有些逆天,就算我们有所谓的右左法则,但是我觉得用typedef简化复杂类型的声明也是合理的
函数如其名,我们为每一个状态新增了对应的进入函数跟退出函数。
1 | static void entry_closed(void) { |
当然,在这个简单的demo中,它们也仅仅就只是打印了一些我们需要的文本而已
1 | void fsm_init(StateMachine *fsm) { |
上篇博客好像没有讲解这个fsm_init函数,这个函数基本上就是初始化了一下我们所要用到的状态机结构体,我们在这个版本的代码中,仅仅只是增加了对于每个状态进入/退出动作的注册。以及对于初始状态的进入动作的手动执行。
我们在这个版本中最重要的变动就是新增了一个函数
1 | static void fsm_transition_to(StateMachine *fsm, State next_state) { |
这个函数专门负责状态机的状态切换,把原本放在状态处理函数里的状态跳转逻辑抽离出来,统一由它管理。
它会自动执行旧状态的退出动作、更新当前状态、再执行新状态的进入动作。
和 fsm_dispatch 思想类似,把进入 / 退出动作封装成函数指针调用,大幅减少新增状态时的重复代码。
透过这种改动,我们现在拥有了转移时自动执行硬件初始化/清理的功能,并且将硬件操作与状态绑定,而非与事件绑定。
我们在下一篇博客中,将会给这个框架新增层次状态的功能。