State machine是很常見的應用/Pattern,這章節會根據下面的圖來實作State machine pattern
enum state { STATE_INITIAL = 0, STATE_1, STATE_2, STATE_3, STATE_4, }; enum event { E1 = 1, E2, E3, E4, };先定義State Machine狀態與Event
struct instance_data { enum event evt; int data; }; struct instance { enum state cur_state; struct instance_data data; };定義一個struct來儲存"現在狀態",Event與data
typedef enum state state_func_t(struct instance_data *data); state_func_t* const state_table[] = { [STATE_INITIAL] = in_init, [STATE_1] = in_state_1, [STATE_2] = in_state_2, [STATE_3] = in_state_3, [STATE_4] = in_state_4, }; void run_state(struct instance *inst) { inst->cur_state = state_table[inst->cur_state](&(inst->data)); };建立一個Table,將每一個state對應的function填入,run_state()會根據目前的State處理該event/data,並回傳下一個狀態
enum state in_state_1(struct instance_data *data) { printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt); switch (data->evt) { case E1: printf("change to S2\n"); return do_s2(); case E2: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do nothing\n"); return STATE_1; } } enum state in_state_2(struct instance_data *data) { printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt); switch (data->evt) { case E3: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do s2 again\n"); return do_s2(); // do s2 again } } enum state in_state_3(struct instance_data *data) { printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt); switch (data->evt) { case E2: printf("change to S4\n"); return do_s4(); default: printf("keep the same STATE && do nothing\n"); return STATE_3; } } enum state in_state_4(struct instance_data *data) { printf("%s(#%d): got EVT:%d\n", __FUNCTION__, __LINE__, data->evt); switch (data->evt) { case E1: printf("change to S2\n"); return do_s2(); case E3: printf("change to S1\n"); return do_s1(); default: printf("keep the same STATE && do again\n"); return do_s4(); } }定義每一個狀態中的行為
enum state do_s1(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_1; } enum state do_s2(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_2; } enum state do_s3(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_3; } enum state do_s4(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_4; } enum state in_init(struct instance_data *data) { printf("%s(#%d): do some init. E:%d\n", __FUNCTION__, __LINE__, data->evt); printf("change to S1\n"); return STATE_1; }定義進入每一個狀態要執行的動作
int main( void ) { int ch; struct instance inst = {STATE_INITIAL, 0}; while ( 1 ) { run_state(&inst); // do other program logic, run other state machines, etc printf("MENU: E1/E2/E3/E4\n"); while(((ch = getc(stdin)) == '\n') || (ch <= '0') || (ch > '4')); inst.data.evt = ch - '0'; } }main function模擬State Machine收到不同event(1~4)
以下是收到event 1, 2, 3, 4的執行結果