State Machine in Software Design

Source: Internet
Author: User
Tags fsm

1. Introduction to the state machine

The concept of a state machine in software design generally refers to a finite state machine (finite-state machine), also known as a finite state machine (FSM, it is a mathematical model that represents a finite state and the transfer and action between these States.

FSM (Finite State Machine) can be represented by a state machine diagram in UML. You can also use status transfer tables in the following format. The following shows the most common representation: the combination of the current State (B) and event (Y) indicates the next state (C ).

Status transfer table

Current Status →
Event failover

Status

Status B

Status C

Event X

...

...

...

Event Y

...

Status C

...

Event Z

...

...

...

The state machine has two important concepts:Status, event. The following is a simple example of a cdnserver:

Cdnserver status transfer table

Status →
Event failover

Play

Pause

Stop

Press keys

...

Play

Play

Press the stop key

Stop

Stop

...

Press keys

Pause

...

...

Through this table, we can intuitively understand the state machine as follows:

1. Simple cdns generally have three statuses: Play, pause, and stop.

2. The operations we perform on the CD server are events. In simple terms, there are three types of events: press the playback, stop, and pause buttons.

3. In different States of the CD server, different events occur (press different buttons), the events triggered and the next state (that is, status transfer) of the CD server are different.

4. as shown in the preceding table, if the current status of the CD server is "playing", press the playback key to maintain the "playing" status without status transfer. If you press the playback key, status transfer is triggered, and the status of the CD server is "paused. Similarly, pressing the stop key will move to the stop state.

II. Implementation of the State Machine

In many cases, the concept of "status" is involved in software development. For example, if the software used to monitor the server has the following options: 'start', 'shutdown ', 'Load too high' and so on.

The software that executes the task. For each task, there are statuses such as "in queue", "prepare", "run", "completed", and "failed, in different states, status migration and the corresponding logic are different when different events occur for a task. For example, in the "queue" status, an "cancel task" event occurs ", in this case, you only need to remove the task from the queue and change the status to "failed. Similarly, when an event "cancel a task" occurs in the "running" status, you need to do a lot of work, such as recycling resources for running tasks.

In general, the concept of a state machine may not be involved if the State is few. However, if there are many States and events and the state machine is not well designed, software development will be very difficult in the future. Subsequent maintenance and upgrades are also a problem.

The implementation of the state machine mainly involves the following methods. Here I will illustrate the implementation of the state machine using the example of the CD server in Chapter 1.

Note: Here I mainly describe the code written in python or C language. In actual use, it works in any language. The key is logical thinking.

1. if... else .....PS: the most tedious way (personal dislike)

#!/usr/bin/pythonclass CDStatus:    RUNNING = 0    STOP = 1    PAUSE = 2class CDEvent:    PRESS_RUNNING = 0    PRESS_STOP = 1    PRESS_PAUSE = 2def do_change_stop():    #TODO someting and change CD status to STOP    print "Chang CD to 'stop' status"def do_change_running():    #TODO someting and change CD status to RUNNING    print "Chang CD to 'running' status"def do_change_pause():    #TODO someting and change CD status to PAUSE    print "Chang CD to 'pause' status"def dispather(curr_status, event):    if curr_status == CDStatus.RUNNING:        if event == CDEvent.PRESS_STOP:            do_change_stop()        elif event == CDEvent.PRESS_PAUSE:            do_change_pause()    elif curr_status == CDStatus.STOP:        if event == CDEvent.PRESS_RUNNING:            do_change_running()        elif event == CDEvent.PRESS_PAUSE:            do_change_pause()    elif curr_status == CDStatus.PAUSE:        if event == CDEvent.PRESS_RUNNING:            do_change_running()        elif event == CDEvent.PRESS_STOP:            do_change_stop()    else:        print "error!"def main():    current_status = CDStatus.STOP    event = CDEvent.PRESS_RUNNING    dispather(current_status, event)    returnif __name__ == "__main__":    main()

As you can see, this example is extremely cumbersome. if... else also needs to nest two layers to determine the outer layer and the internal layer to determine the event. Finally, it uses the current status and events, corresponding to the "cdnserver status migration table", and handles the event and transfer status.

This method is not flexible, because every time a State is added, a bunch of if. else judgments are added.


2. switch... case .....Python does not have the switch syntax and can be replaced by dict. Here I will describe it in General C language.

The following code can be compiled and run directly. In dispather, two-layer switches are nested, similar to the structure of if... else above, but changed to switch.

# Include
 
  
# Include
  
   
# Include
   
    
Typedef enum {STOP = 0, RUNNING, PAUSE,} CD_STATE; typedef enum {PRESS_RUNNING = '0', PRESS_PAUSE = '1', PRESS_STOP = '2',} CD_EVENT; char state_to_str [3] [100] = {"STOP", "RUNNING", "PAUSE"}; // global variable used to store the current state of the CD int current_state = STOP; void do_change_running () {printf ("CD Status from % s to RUNING \ n", state_to_str [current_state]); current_state = RUNNING;} void do_change_stop () {printf ("CD Status from '% s 'To STOP \ n ", state_to_str [current_state]); current_state = STOP;} void do_change_pause () {printf (" CD Status from' % s' to pause \ n ", state_to_str [current_state]); current_state = PAUSE;} int dispather (current_state, event) {switch (current_state) {case STOP: switch (event) {case PRESS_RUNNING: do_change_running (); break; case PRESS_PAUSE: do_change_pause (); break; default: printf ("CD's state not ch Ange \ n "); break;} break; case PAUSE: switch (event) {case PRESS_RUNNING: do_change_running (); break; case PRESS_STOP: do_change_stop (); break; default: printf ("CD's state not change \ n"); break;} break; case RUNNING: switch (event) {case PRESS_PAUSE: do_change_pause (); break; case PRESS_STOP: do_change_stop (); break; default: printf ("CD's state not change \ n"); break;} break; default: printf ("Err Or! No such status! \ N "); break ;}} int main () {char ch = '0'; printf (" enter a number to operate the cdnserver (0: RUNNING, 1: PAUSE, 2: STOP): \ n "); while (1) {ch = getchar (); if (ch = '\ n ') {} else if (ch <'0') | (ch> '3') {printf ("illegal input. Please enter it again! \ N "); continue;} else {char event = ch; dispather (current_state, event); printf (" enter a number to operate the CD server (0: RUNNING, 1: PAUSE, 2: STOP): \ n ") ;}} return 0 ;}
   
  
 

3.Function pointer MethodThis method is my most common and favorite. So here I will post the C and python code separately for detailed explanation.

Take a closer look at the "cdnserver status transition diagram" in Chapter 1. It is actually a two-dimensional matrix structure. The two-dimensional matrix structure corresponds to the data structure, which is nothing more than a two-dimensional array. There are corresponding logic processing for state conversion. Therefore, we can use the two-dimensional function pointer to implement the state conversion graph. Here I didn't use a two-dimensional array, and I used a struct array, which is more intuitive.

If a new State is added, you only need to add a new state, event, and processing function to the array state_mechine.

# Include
 
  
# Include
  
   
# Include
   
    
Typedef enum {STOP = 0, RUNNING, PAUSE, MAX_STATE,} CD_STATE; typedef enum {PRESS_RUNNING = 0, PRESS_PAUSE, PRESS_STOP, MAX_EVENT,} CD_EVENT; char state_to_str [3] [100] = {"STOP", "RUNNING", "PAUSE"}; struct CD_STATE_MECHINE {int state; int event; void (* func) (unsigned char *);}; void do_change_running (unsigned char * user_data); void do_change_stop (unsigned char * user_data); void do_change_pause (unsign Ed char * user_data); struct =state_mechine [] ={ RUNNING, PRESS_RUNNING, NULL}, {RUNNING, PRESS_STOP, do_change_stop}, {RUNNING, PRESS_PAUSE, do_change_pause}, {PAUSE, PRESS_RUNNING, do_change_running}, {PAUSE, PRESS_STOP, do_change_stop}, {PAUSE, PRESS_PAUSE, NULL}, {STOP, PRESS_RUNNING, do_change_running}, {STOP, PRESS_STOP, NULL}, {STOP, PRESS_PAUSE, do_change_pause}, {-1,-1, NULL },}; // global variable, used to store the current state of the CD int current_state = STOP; void do_change_running (unsigned char * user_data) {printf ("CD Status from % s to RUNING \ n", state_to_str [current_state]); current_state = RUNNING;} void do_change_stop (unsigned char * user_data) {printf ("CD Status from '% s' to STOP \ n", state_to_str [current_state]); current_state = STOP;} void do_change_pause (unsigned char * user_data) {printf ("CD Stat Us from '% s' to pause \ n ", state_to_str [current_state]); current_state = PAUSE;} int dispather (current_state, event) {int I = 0; for (I = 0; state_mechine [I]. state! =-1; I ++) {if (current_state = state_mechine [I]. state & event = state_mechine [I]. event) {void (* func) (unsigned char *); func = state_mechine [I]. func; if (func! = NULL) {func (NULL);} else {printf ("state not change! \ N ") ;}break ;}} int main () {char ch = '0'; printf (" enter a number to operate the CD server (0: RUNNING, 1: PAUSE, 2: STOP): \ n "); while (1) {ch = getchar (); if (ch = '\ n ') {} else if (ch <'0') | (ch> '3') {printf ("illegal input. Please enter it again! \ N "); continue;} else {int event = ch-'0'; dispather (current_state, event); printf (" enter a number to operate the CD server (0: RUNNING, 1: PAUSE, 2: STOP): \ n ") ;}} return 0 ;}
   
  
 

I am writing this article for the time being. I will try again later and add the python version of the state machine implementation.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.