Teach you step by step, implement process 5 state model in C language

foreword

State machines are widely used in actual work development. When I first entered the company, when I made a flow chart based on the company's products, I found that I often missed one or another state, which led to problems in the overall process. Later I knew the state. For something like a machine, I found that this picture can clearly express the flow of the entire state.

Yikoujun has done many network protocol modules, and the development of many protocols must use state machines; a robust state machine can make your program not suddenly enter an unpredictable program branch no matter what emergencies occur .

This article implements a simple state machine of the process 5 state model through C language, so that you can familiarize yourself with the charm of the state machine.

What is a state machine?

definition

State machine is the abbreviation of finite state automata, which is a mathematical model abstracted from the running rules of real things.

Let's first explain what a "state" is. Real things have different states, such as an LED, etc., there are two states of on and off. What we usually call a state machine is a finite state machine, that is, the number of states of things being described is limited, for example, the state of an LED light is two on and off.

A state machine, or State Machine, does not refer to an actual machine, but to a mathematical model. To put it bluntly, it generally refers to a state transition diagram.

Example

Taking the light bulb diagram of physics class as an example, it is a basic small state machine.

 The following state machine diagram can be drawn

 

Here are two states: ① the light bulb is on, ② the light bulb is off If the switch is turned on, then the state will switch to the light bulb on. If the switch is turned off while the light bulb is on, the state will switch to light bulb off.

The full name of state machine is finite state automata, and the word "automatic" also contains important meanings. Given a state machine, given its current state and input, the output state can be clearly calculated. For example, for a light bulb, given the initial state that the light bulb is off, and the given input "turn on the switch", then the next state can be calculated.

Four concepts

The four concepts of state machine are given below.

  1. State , the state. A state machine must contain at least two states. For example, in the light bulb example above, there are two states: the light bulb is on and the light bulb is off.

  2. Event , the event. An event is a trigger or a password to perform an action. For a light bulb, "turning on the switch" is an event.

  3. Action , the action. Actions to be performed after an event occurs. For example the event is "turn on the switch" and the action is "turn on the light". When programming, an Action generally corresponds to a function.

  4. Transition , transformation. That is, changing from one state to another. For example, the "light-on process" is a transformation.

Application of state machine

The state machine is an abstraction of the real world, and it is a logically rigorous mathematical abstraction, so it is obviously very suitable for use in the digital field. It can be applied to various levels, such as hardware design, compiler design, and programming to implement various specific business logic.

Process 5 State Model

Process management is one of the five major subsystems of Linux. It is very important and very complicated to implement. Let's see how the process switches states.

The following figure is the 5-state model of the process:

 A brief introduction to this figure is as follows:

  1. Runnable state: When the process is being executed by the CPU, or is ready to be executed by the scheduler at any time, the process is said to be in the running state (running). Processes can run in kernel mode or in user mode. When the system resources are available, the process is awakened and enters the ready-to-run state, which is called the ready state.

  2. Light sleep state (interruptible): The process is sleeping (blocked), waiting for the arrival of resources to wake up, or it can wake up through other process signals or clock interrupts and enter the run queue.

  3. Deep sleep state (uninterruptible): It is basically similar to light sleep, but one thing is that it cannot be awakened by other process signals or clock interrupts. Transition to a runnable ready state is only possible when explicitly woken up using the wake_up() function.

  4. Suspended state: The process enters the suspended state when it receives the signal SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU. The SIGCONT signal can be sent to it to make the process transition to the runnable state.

  5. Zombie state: When a process has stopped running, but its parent process has not asked its status, and the PCB is not released, the process is said to be in a zombie state.

The state of the process is switched according to this state diagram.

The state flow is a bit complicated, because our goal is to implement a simple state machine, so let's simplify the state machine as follows:

 To implement a state machine, first convert the state machine into the following state transition table.

 

The brief description is as follows: Assuming that the current process is in the running state, only after the schedule event occurs, the process will migrate to the owencpu state. If other events occur in this state, such as wake and wait_event Does not cause state transitions.

As shown in FIG:

  1. Each column represents a state, and each row corresponds to an event.

  2. This table is the core diagram for implementing the state machine. Please compare the relationship between this table and the state transition diagram in detail.

  3. In the actual scene, the process switching will be far more complicated than this picture. Fortunately, many great gods have helped us solve these complex problems. We only need to stand on the shoulders of giants.

accomplish

According to the state transition table, the states of the state machine are defined as follows:

typedef enum {
  sta_origin=0,
  sta_running,
  sta_owencpu,
  sta_sleep_int,
  sta_sleep_unint
}State;

The events that happened are as follows:

typedef enum{
  evt_fork=0,
  evt_sched,
  evt_wait,
  evt_wait_unint,
  evt_wake_up,
  evt_wake, 
}EventID;

Whether it is a state or an event, it can be adjusted according to the actual situation.

Define a structure to represent the current state transition information:

typedef struct {
  State curState;//当前状态
  EventID eventId;//事件ID
  State nextState;//下个状态
  CallBack action;//回调函数,事件发生后,调用对应的回调函数
}StateTransform ; 

Event callback function: In practical applications, different events need to be executed with different actions, so different functions need to be defined. For the sake of convenience, all events in this example use the same callback function. Function: Print the status of the process before and after the event occurs. If the status changes, call the corresponding callback function.

void action_callback(void *arg)
{
 StateTransform *statTran = (StateTransform *)arg;
 
 if(statename[statTran->curState] == statename[statTran->nextState])
 {
  printf("invalid event,state not change\n");
 }else{
  printf("call back state from %s --> %s\n",
   statename[statTran->curState],
   statename[statTran->nextState]);
 }
}

Define an array of migration tables for each state:

/*origin*/
StateTransform stateTran_0[]={
 {sta_origin,evt_fork,        sta_running,action_callback},
 {sta_origin,evt_sched,       sta_origin,NULL},
 {sta_origin,evt_wait,        sta_origin,NULL},
 {sta_origin,evt_wait_unint,  sta_origin,NULL},
 {sta_origin,evt_wake_up,     sta_origin,NULL},
 {sta_origin,evt_wake,        sta_origin,NULL},
}; 

/*running*/
StateTransform stateTran_1[]={
 {sta_running,evt_fork,        sta_running,NULL},
 {sta_running,evt_sched,       sta_owencpu,action_callback},
 {sta_running,evt_wait,        sta_running,NULL},
 {sta_running,evt_wait_unint,  sta_running,NULL},
 {sta_running,evt_wake_up,     sta_running,NULL},
 {sta_running,evt_wake,        sta_running,NULL},
}; 
/*owencpu*/
StateTransform stateTran_2[]={
 {sta_owencpu,evt_fork,        sta_owencpu,NULL},
 {sta_owencpu,evt_sched,       sta_owencpu,NULL},
 {sta_owencpu,evt_wait,        sta_sleep_int,action_callback},
 {sta_owencpu,evt_wait_unint,  sta_sleep_unint,action_callback},
 {sta_owencpu,evt_wake_up,     sta_owencpu,NULL},
 {sta_owencpu,evt_wake,        sta_owencpu,NULL},
}; 

/*sleep_int*/
StateTransform stateTran_3[]={
 {sta_sleep_int,evt_fork,        sta_sleep_int,NULL},
 {sta_sleep_int,evt_sched,       sta_sleep_int,NULL},
 {sta_sleep_int,evt_wait,        sta_sleep_int,NULL},
 {sta_sleep_int,evt_wait_unint,  sta_sleep_int,NULL},
 {sta_sleep_int,evt_wake_up,     sta_sleep_int,NULL},
 {sta_sleep_int,evt_wake,        sta_running,action_callback},
}; 
/*sleep_unint*/
StateTransform stateTran_4[]={
 {sta_sleep_unint,evt_fork,        sta_sleep_unint,NULL},
 {sta_sleep_unint,evt_sched,       sta_sleep_unint,NULL},
 {sta_sleep_unint,evt_wait,        sta_sleep_unint,NULL},
 {sta_sleep_unint,evt_wait_unint,  sta_sleep_unint,NULL},
 {sta_sleep_unint,evt_wake_up,     sta_running,action_callback},
 {sta_sleep_unint,evt_wake,        sta_sleep_unint,NULL},
}; 

Implement the event generation function:

void event_happen(unsigned int event)
功能:
 根据发生的event以及当前的进程state,找到对应的StateTransform 结构体,并调用do_action()
void do_action(StateTransform *statTran)
功能:
 根据结构体变量StateTransform,实现状态迁移,并调用对应的回调函数。
#define STATETRANS(n)  (stateTran_##n)
/*change state & call callback()*/
void do_action(StateTransform *statTran)
{
 if(NULL == statTran)
 {
  perror("statTran is NULL\n");
  return;
 }
 //状态迁移
 globalState = statTran->nextState;
 if(statTran->action != NULL)
 {//调用回调函数
  statTran->action((void*)statTran);
 }else{
  printf("invalid event,state not change\n");
 }
}
void event_happen(unsigned int event)
{
 switch(globalState)
 {
  case sta_origin:
   do_action(&STATETRANS(0)[event]);
   break;
  case sta_running:
   do_action(&STATETRANS(1)[event]);
   break;
  case sta_owencpu:
   do_action(&STATETRANS(2)[event]); 
   break;
  case sta_sleep_int:
   do_action(&STATETRANS(3)[event]); 
   break;
  case sta_sleep_unint:
   do_action(&STATETRANS(4)[event]); 
   break;
  default:
   printf("state is invalid\n");
   break;
 }
}

Test program: Function:

  1. The initial state of the initialization state machine is sta_origin;

  2. Create a child thread and display the current process status every second;

  3. The sequence of events is: evt_fork-->evt_sched-->evt_sched-->evt_wait-->evt_wake.

Readers can follow their own needs, modify the sequence of events, and observe the changes in the state.

main.c

/*显示当前状态*/
void *show_stat(void *arg)
{
 int len;
 char buf[64]={0};
 
 while(1)
 {
  sleep(1);
  printf("cur stat:%s\n",statename[globalState]);
 } 
}
void main(void)
{
 init_machine();
 //创建子线程,子线程主要用于显示当前状态
 pthread_create(&pid, NULL,show_stat, NULL);

 sleep(5);
 event_happen(evt_fork);

 sleep(5);
 event_happen(evt_sched);
 sleep(5);
 event_happen(evt_sched);
 sleep(5);
 event_happen(evt_wait);
 sleep(5);
 event_happen(evt_wake);
 
}

operation result:

It can be seen from the results that:

evt_fork-->evt_sched-->evt_sched-->evt_wait-->evt_wake

The state transition sequence corresponding to the sequence of events is:

origen-->running-->owencpu-->owencpu-->sleep_int-->running

Guess you like

Origin blog.csdn.net/yx5666/article/details/127411032