小言_互联网的博客

c++状态机的使用

654人阅读  评论(0)

什么是状态机

状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。英文名字叫State Machine ,不是指一台实际机器,一般就是指一张状态转换图。全称是有限状态自动机,自动两个字包含重要含义。给定一个状态机,同时给定它的当前状态以及输入,那么输出状态时可以明确的运算出来的,当输入条件时,能输出下一个状态。

现实事物是有不同状态,例如一个LED等,就有 亮 和 灭两种状态。我们通常所说的状态机是有限状态机,也就是被描述的事物的状态的数量是有限个,例如LED灯的状态就是两个亮和 灭。

为什么用状态机

状态机解决的问题就是当某种模型的状态变更比较比较复杂,且状态比较多,那么我们有必要将这些状态变化的逻辑抽象出来,做成一个可以统一调用的算法,这样封装出来的代码就比较好维护,同时可读性也很强。

状态机在实际工作开发中很有用,应用也非常广泛。一个健壮的状态机可以让你的程序,不论发生何种突发事件都不会突然进入一个不可预知的程序分支,可以很清晰的表达整个状态的流转。

在GUI应用程序、Web应用程序等事件驱动型的应用程序,采用状态机的思路来完成程序设计,可以简化设计流程,使程序的可读性、可维护性都得到增加。

 使用状态机有哪些好处?
1. 当一个程序有多个状态时,规范了状态机的状态转换,避免了一些引入一些复杂的判断逻辑。
2. 规范了程序在不同状态下所能提供的能力。
3. 在能力上可以进行横向扩展,提供新的状态来完善现有逻辑。

简单状态机的实现

使用switch跳转即可实现一种简单的状态机。如果逻辑不是很复杂,使用switch语句也能达到实现目的。举例如下:


  
  1. enum state
  2. {
  3. nullState_,
  4. firstState_,
  5. secondState_,
  6. thirdState_,
  7. quitState_,
  8. };
  9. struct param_t
  10. {
  11. int param1;
  12. int param2;
  13. // ......
  14. };
  15. int nullStateProc(param_t& param){
  16. return firstState_;
  17. }
  18. int firstStateProc(param_t& param){
  19. return secondState_;
  20. }
  21. int secondStateProc(param_t& param){
  22. return secondState_;
  23. }
  24. int thirdStateProc(param_t& param){
  25. return secondState_;
  26. }
  27. int quitEvent(){
  28. return nullState_;
  29. }
  30. int stateMachine(state& state_, param_t& param){
  31. switch (state_)
  32. {
  33. case nullState_:
  34. state_ = static_cast<state>( nullStateProc(param));
  35. break;
  36. case firstState_:
  37. state_ = static_cast<state>( firstStateProc(param));
  38. break;
  39. case secondState_:
  40. state_ = static_cast<state>( secondStateProc(param));
  41. break;
  42. case thirdState_:
  43. state_ = static_cast<state>( thirdStateProc(param));
  44. break;
  45. case quitState_:
  46. quitEvent();
  47. return 0;
  48. }
  49. return 1;
  50. }
  51. void start()
  52. {
  53. state state_ = nullState_;
  54. param_t param{};
  55. while ( true)
  56. {
  57. auto stateResult = stateMachine(state_, param);
  58. if (!stateResult)
  59. {
  60. return;
  61. }
  62. }
  63. }

另一种简单实现

如果需要管理的状态和事件比较多,需要逻辑清晰和便于维护,使用简单的switch可能无法满足需求。这里介绍一种简单的实现,消除庞大的条件分支语句,从配置表容易看出各个状态的转换图。


  
  1. /* statemachine.h*/
  2. #ifndef _STATEMACHINE_H_
  3. #define _STATEMACHINE_H_
  4. #include <iostream>
  5. enum EventActionResult {
  6. EventFailed, EventProcessedOK
  7. };
  8. template< class T, class P>
  9. class State {
  10. public:
  11. std::string inputEvent;
  12. State<T, P> *nextState;
  13. EventActionResult (T::*action)( const std::string &event, P *param);
  14. State<T, P> *errorState;
  15. };
  16. template< class T, class P>
  17. class StateMachine {
  18. private:
  19. State<T, P> *init;
  20. State<T, P> *current;
  21. T *target;
  22. public:
  23. StateMachine() {}
  24. void Init(T *_target, State<T, P> *initialState) {
  25. init = current = initialState;
  26. target = _target;
  27. }
  28. void Reset() {
  29. current = init;
  30. }
  31. void ProcessEvent(const std::string &event, P *param) {
  32. for (State<T, P> *p = this->current; p->nextState != NULL; p++) {
  33. if (p->inputEvent == event) {
  34. if (p->action != NULL) {
  35. if (EventFailed == ( this->target->*(p->action))(event, param)) {
  36. if (p->errorState != NULL) {
  37. //Only if there's an errorstate defined. Otherwise, just do nothing
  38. this->current = p->errorState;
  39. }
  40. return;
  41. }
  42. }
  43. this->current = p->nextState;
  44. return;
  45. }
  46. }
  47. //Event not found. Do nothing
  48. return;
  49. }
  50. };

以下是使用举例:


  
  1. class MyStateMachine {
  2. public:
  3. struct param_t {
  4. int param;
  5. int param1;
  6. int param2;
  7. };
  8. StateMachine<MyStateMachine, param_t> stMachine;
  9. EventActionResult HandleEvent1(const std::string &e, param_t *param);
  10. EventActionResult HandleEvent2(const std::string &e, param_t *param);
  11. EventActionResult HandleEventA(const std::string &e, param_t *param);
  12. EventActionResult HandleEventB(const std::string &e, param_t *param);
  13. EventActionResult HandleThree(const std::string &e, param_t *param);
  14. void HandleEvent(const std::string &e, param_t *param);
  15. void Init();
  16. void Start();
  17. };

  
  1. #include "statemachine.h"
  2. #include <cstdlib>
  3. #include <iostream>
  4. #include <stdio.h>
  5. typedef State<MyStateMachine, MyStateMachine:: param_t> STATE;
  6. extern STATE Idle[];
  7. extern STATE One[];
  8. extern STATE Two[];
  9. STATE Idle[] =
  10. {
  11. //EVENT,NEXT, ACTION, ERRORSTATE (where to land if there's an error)
  12. { "event1", One, &MyStateMachine::HandleEvent1, Idle},
  13. { "event2", Two, &MyStateMachine::HandleEvent2, Idle},
  14. { "", NULL, NULL, NULL}, //End of table
  15. };
  16. STATE One[] =
  17. {
  18. { "eventA", Idle, &MyStateMachine::HandleEventA, Idle},
  19. { "eventB", Idle, &MyStateMachine::HandleEventB, Idle},
  20. { "", NULL, NULL, NULL},
  21. };
  22. STATE Two[] =
  23. {
  24. { "eventC", Idle, NULL, NULL},
  25. { "", NULL, NULL, NULL},
  26. };
  27. EventActionResult MyStateMachine::HandleEvent1(const std::string &e, param_t *param) {
  28. std::cout << "HandleEvent1,param:" << param->param << std::endl;
  29. return EventProcessedOK;
  30. }
  31. EventActionResult MyStateMachine::HandleEvent2(const std::string &e, param_t *param) {
  32. std::cout << "HandleEvent2,param:" << param->param << std::endl;
  33. return EventProcessedOK;
  34. }
  35. EventActionResult MyStateMachine::HandleEventA(const std::string &e, param_t *param) {
  36. std::cout << "HandleEventA,param:" << param->param << std::endl;
  37. return EventProcessedOK;
  38. }
  39. EventActionResult MyStateMachine::HandleEventB(const std::string &e, param_t *param) {
  40. std::cout << "HandleEventB,param:" << param->param << std::endl;
  41. return EventProcessedOK;
  42. }
  43. EventActionResult MyStateMachine::HandleThree(const std::string &e, param_t *param) {
  44. std::cout << "HandleThree" << std::endl;
  45. return EventProcessedOK;
  46. }
  47. void MyStateMachine::HandleEvent(const std::string &e, param_t *param) {
  48. stMachine. ProcessEvent(e, param);
  49. }
  50. void MyStateMachine::Init() {
  51. stMachine. Init( this, Idle);
  52. }
  53. void MyStateMachine::Start() {
  54. while ( 1) {
  55. char c[ 255];
  56. // 模拟输入event
  57. std::cin. getline(c, 255);
  58. std::string event{c};
  59. MyStateMachine:: param_t param;
  60. param.param = 1;
  61. this-> HandleEvent(event, &param);
  62. }
  63. }

引用

什么是状态机?_pingxiaozhao的博客-CSDN博客_状态机的概念

为Linux应用构造有限状态机_wowocpp的博客-CSDN博客_linux 状态机

有限状态机详解(转载)_白小狮的博客-CSDN博客_有限状态机和无限状态机

Linux进程是如何创建出来的?

为Linux操作系统应用构造有限状态机方法-红联Linux系统门户

一文详解 Android状态机StateMachine 使用方式及实现原理_bjxiaxueliang的博客-CSDN博客_statemachine

c++写状态机_zhi_cary的博客-CSDN博客_c++ 状态机

C++有限状态机的实现_Valreaper的博客-CSDN博客_c++ 状态机

github经典C++状态机(fsm)源代码剖析_star-keke的博客-CSDN博客

用C++来实现有限状态机(附代码)_李肖遥的博客-CSDN博客

TinyFSM 介绍_百思可乐的博客-CSDN博客

C++状态机框架实现 - 灰信网(软件开发博客聚合)

状态模式(state)C++实现_shu_chang1993的博客-CSDN博客_c++state

c++写状态机_zhi_cary的博客-CSDN博客_c++ 状态机


转载:https://blog.csdn.net/qq8864/article/details/128204140
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场