第一次写状态机,参考现有代码写了一个框架,在网上看了一些例子,结果就陷入了纠结中,不知道状态机哪种形式比较好,是不是还缺少什么,各位大牛有什么建议敬请回复,我会持续更新,非常感谢!
第一种形式: 所有的状态通过if...else来跳转,主线程收到消息之后会进入当前状态进行处理,在一大堆的if...else里面理出整个状态的迁移过程比较痛苦;
第二种形式: 通过switch...case,等价于if...else,(个人理解switch...case就是if...else的优雅写法);
第三种形式: 所有状态维护在一个列表中,外部事件处理与状态切换统一处理,比较容易分析;
代码比较简单,而且只有百行,没有写注释,请大家见谅,实现的状态切换如下:
IDLE-------EventX---->StateA
StateA-----EventY---->StateB;
StateA-----EventX---->IDLE;
1 #include <stdio.h> 2 #include <assert.h> 3 4 #define MAX_STATE_NAME_LEN (32) 5 6 enum ErrorCode 7 { 8 EOK = 0, 9 EBADVALUE = -1, 10 }; 11 12 typedef enum Event 13 { 14 Event_X = 1, 15 Event_Y = 2, 16 Event_Z = 3, 17 }Event; 18 19 typedef enum State 20 { 21 STATE_IDLE = 0x0, 22 STATE_A = 0x1, 23 STATE_B = 2, 24 STATE_INVALID = 3, 25 }State; 26 27 struct FsmContext; 28 typedef int (*fsm_handler)(struct FsmContext *pctxt, Event, void *data); 29 30 struct FsmTable 31 { 32 State curState; 33 Event evt; 34 State nextState; 35 char curStateName[MAX_STATE_NAME_LEN]; 36 fsm_handler handler; 37 }; 38 39 struct FsmContext 40 { 41 State curState; 42 State prevState; 43 struct FsmTable *pfsmTable; 44 }; 45 46 int fsm_handler_state_idle(struct FsmContext *pctxt, Event, void *data); 47 int fsm_handler_state_a(struct FsmContext *pctxt, Event, void *data); 48 int fsm_handler_state_b(struct FsmContext *pctxt, Event, void *data); 49 50 struct FsmTable fsmTable[] = 51 { 52 /*CurState Event NextState CurStateName Handler*/ 53 {STATE_IDLE, Event_X, STATE_A, "STATE_IDLE", fsm_handler_state_idle}, 54 {STATE_A, Event_Y, STATE_B, "STATE_A", fsm_handler_state_a}, 55 {STATE_A, Event_X, STATE_IDLE, "STATE_A", fsm_handler_state_a}, 56 {STATE_B, Event_Z, STATE_A, "STATE_B", fsm_handler_state_b}, 57 }; 58 59 struct FsmTable *g_pTable = fsmTable; 60 struct FsmContext ctxt; 61 struct FsmContext *g_pCtxt = &ctxt; 62 63 int fsm_init(struct FsmTable *ptable, struct FsmContext *pctxt) 64 { 65 assert(ptable); 66 assert(pctxt); 67 68 pctxt->curState = STATE_IDLE; 69 pctxt->prevState = STATE_INVALID; 70 pctxt->pfsmTable = ptable; 71 72 return EOK; 73 } 74 75 int fsm_state_transfer(struct FsmTable *ptable, struct FsmContext *pctxt, State nextState) 76 { 77 assert(ptable); 78 assert(pctxt); 79 pctxt->prevState = pctxt->curState; 80 pctxt->curState = nextState; 81 return EOK; 82 } 83 84 struct FsmTable * fsm_get_handler(struct FsmTable *ptable, State curState, Event evt) 85 { 86 assert(ptable); 87 struct FsmTable *p = ptable; 88 int i = 0x0; 89 int num = sizeof(fsmTable)/sizeof(fsmTable[0]); 90 91 for(i = 0x0; i < num; i++) 92 { 93 if(NULL != p && p->curState == curState && p->evt == evt) 94 { 95 return p; 96 } 97 p++; 98 } 99 return NULL; 100 } 101 102 int fsm_evt_handler(struct FsmTable *ptable, struct FsmContext *pctxt, Event evt, void *data) 103 { 104 assert(ptable); 105 assert(pctxt); 106 assert(data); 107 struct FsmTable *p = NULL; 108 109 p = fsm_get_handler(ptable, pctxt->curState, evt); 110 111 if(NULL != p) 112 { 113 if(NULL != p->handler) 114 { 115 p->handler(pctxt, evt, data); 116 } 117 fsm_state_transfer(ptable, pctxt, p->nextState); 118 } 119 else 120 { 121 return EBADVALUE; 122 } 123 124 return EOK; 125 } 126 127 int fsm_handler_state_idle(struct FsmContext *pctxt, Event evt, void *data) 128 { 129 assert(pctxt); 130 assert(data); 131 printf("prev state:%d, cur state:%d, evt:%d, data:%s\n", pctxt->prevState, pctxt->curState, evt, (char*)data); 132 return EOK; 133 } 134 135 int fsm_handler_state_a(struct FsmContext *pctxt, Event evt, void *data) 136 { 137 assert(pctxt); 138 assert(data); 139 printf("prev state:%d, cur state:%d, evt:%d, data:%s\n", pctxt->prevState, pctxt->curState, evt, (char*)data); 140 return EOK; 141 } 142 143 int fsm_handler_state_b(struct FsmContext *pctxt, Event evt, void *data) 144 { 145 assert(pctxt); 146 assert(data); 147 printf("prev state:%d, cur state:%d, evt:%d, data:%s\n", pctxt->prevState, pctxt->curState, evt, (char*)data); 148 return EOK; 149 } 150 151 int main(void) 152 { 153 fsm_init(g_pTable, g_pCtxt); 154 Event evt = Event_X; 155 char *data = "hello world"; 156 157 fsm_evt_handler(g_pTable, g_pCtxt, Event_X, (void*)data); 158 fsm_evt_handler(g_pTable, g_pCtxt, Event_X, (void*)data); 159 fsm_evt_handler(g_pTable, g_pCtxt, Event_X, (void*)data); 160 fsm_evt_handler(g_pTable, g_pCtxt, Event_Y, (void*)data); 161 fsm_evt_handler(g_pTable, g_pCtxt, Event_Z, (void*)data); 162 163 return EOK; 164 }