Enseñarle paso a paso, implementar el modelo de estado del proceso 5 en lenguaje C

prefacio

Las máquinas de estados se utilizan ampliamente en el desarrollo del trabajo real. Cuando ingresé por primera vez a la empresa, cuando hice un diagrama de flujo basado en los productos de la empresa, descubrí que a menudo me perdía uno u otro estado, lo que generaba problemas en el proceso general. Más tarde Conocía el estado Para algo como una máquina, descubrí que esta imagen puede expresar claramente el flujo de todo el estado.

Yikoujun ha realizado muchos módulos de protocolo de red, y el desarrollo de muchos protocolos debe usar máquinas de estado; una máquina de estado robusta puede hacer que su programa no entre repentinamente en una rama de programa impredecible sin importar las emergencias que ocurran.

Este artículo implementa una máquina de estado simple del modelo de estado de proceso 5 a través del lenguaje C, para que pueda familiarizarse con el encanto de la máquina de estado.

¿Qué es una máquina de estado?

definición

Máquina de estado es la abreviatura de autómata de estado finito, que es un modelo matemático abstraído de las reglas de funcionamiento de las cosas reales.

Primero expliquemos qué es un "estado". Las cosas reales tienen diferentes estados, como un LED, etc., hay dos estados de encendido y apagado. Lo que solemos llamar una máquina de estados es una máquina de estados finitos, es decir, el número de estados de las cosas que se describen es limitado, por ejemplo, el estado de una luz LED es dos encendido y apagado.

Una máquina de estados, o State Machine, no se refiere a una máquina real, sino a un modelo matemático. Para decirlo sin rodeos, generalmente se refiere a un diagrama de transición de estado.

Ejemplo

Tomando como ejemplo el diagrama de la bombilla de la clase de física, se trata de una pequeña máquina de estado básica.

 Se puede dibujar el siguiente diagrama de máquina de estado

 

Aquí hay dos estados: ① la bombilla está encendida, ② la bombilla está apagada Si el interruptor está encendido, entonces el estado cambiará a la bombilla encendida. Si el interruptor se apaga mientras la bombilla está encendida, el estado cambiará a bombilla apagada.

El nombre completo de máquina de estado es autómata de estado finito, y la palabra "automático" también contiene significados importantes. Dada una máquina de estado, dado su estado actual y su entrada, el estado de salida se puede calcular claramente. Por ejemplo, para una bombilla, dado el estado inicial de que la bombilla está apagada y la entrada dada "encender el interruptor", entonces se puede calcular el siguiente estado.

Cuatro conceptos

Los cuatro conceptos de máquina de estado se dan a continuación.

  1. Estado, el estado. Una máquina de estado debe contener al menos dos estados. Por ejemplo, en el ejemplo anterior de la bombilla, hay dos estados: la bombilla está encendida y la bombilla está apagada.

  2. Evento, el evento. Un evento es un activador o una contraseña para realizar una acción. Para una bombilla, "encender el interruptor" es un evento.

  3. Acción, la acción. Acciones a realizar después de que ocurra un evento. Por ejemplo, el evento es "encender el interruptor" y la acción es "encender la luz". Al programar, una Acción generalmente corresponde a una función.

  4. Transición, transformación. Es decir, cambiar de un estado a otro. Por ejemplo, el "proceso de encendido" es una transformación.

Aplicación de máquina de estado

La máquina de estados es una abstracción del mundo real, y es una abstracción matemática lógicamente rigurosa, por lo que obviamente es muy adecuada para su uso en el campo digital. Se puede aplicar a varios niveles, como diseño de hardware, diseño de compiladores y programación para implementar varias lógicas comerciales específicas.

Modelo de estado del proceso 5

La gestión de procesos es uno de los cinco subsistemas principales de Linux, es muy importante y muy complicado de implementar, veamos cómo cambia de estado el proceso.

La siguiente figura es el modelo de 5 estados del proceso:

 Una breve introducción a esta figura es la siguiente:

  1. Estado ejecutable: cuando el proceso está siendo ejecutado por la CPU, o está listo para ser ejecutado por el planificador en cualquier momento, se dice que el proceso está en estado de ejecución (running). Los procesos pueden ejecutarse en modo kernel o en modo usuario. Cuando los recursos del sistema están disponibles, el proceso se activa y entra en el estado listo para ejecutarse, que se denomina estado listo.

  2. Estado de suspensión ligera (interrumpible): el proceso está dormido (bloqueado), esperando la llegada de recursos para despertar, o puede despertar a través de otras señales de proceso o interrupciones de reloj e ingresar a la cola de ejecución.

  3. Estado de sueño profundo (ininterrumpible): Es básicamente similar al sueño ligero, pero una cosa es que no puede ser despertado por otras señales de proceso o interrupciones de reloj. La transición a un estado listo para ejecutarse solo es posible cuando se activa explícitamente mediante la función wake_up().

  4. Estado suspendido: El proceso entra en estado suspendido cuando recibe la señal SIGSTOP, SIGTSTP, SIGTTIN o SIGTTOU. Se le puede enviar la señal SIGCONT para hacer la transición del proceso al estado ejecutable.

  5. Estado zombi: cuando un proceso ha dejado de ejecutarse, pero su proceso principal no ha preguntado su estado y la PCB no se libera, se dice que el proceso está en estado zombi.

El estado del proceso se cambia de acuerdo con este diagrama de estado.

El flujo de estado es un poco complicado, porque nuestro objetivo es implementar una máquina de estado simple, así que simplifiquemos la máquina de estado de la siguiente manera:

 Para implementar una máquina de estado, primero convierta la máquina de estado en la siguiente tabla de transición de estado.

 

La breve descripción es la siguiente: Suponiendo que el proceso actual está en el estado de ejecución, solo después de que ocurra el evento de programación, el proceso migrará al estado owencpu.Si ocurren otros eventos en este estado, como wake y wait_event No causa transiciones de estado.

Como se muestra en la figura:

  1. Cada columna representa un estado y cada fila corresponde a un evento.

  2. Esta tabla es el diagrama central para implementar la máquina de estado. Compare en detalle la relación entre esta tabla y el diagrama de transición de estado.

  3. En la escena real, el cambio de proceso será mucho más complicado que en esta imagen. Afortunadamente, muchos grandes dioses nos han ayudado a resolver estos complejos problemas. Solo necesitamos pararnos sobre los hombros de gigantes.

realizar

Según la tabla de transición de estados, los estados de la máquina de estados se definen de la siguiente manera:

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

Los hechos ocurridos son los siguientes:

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

Ya sea un estado o un evento, se puede ajustar de acuerdo con la situación real.

Defina una estructura para representar la información de transición de estado actual:

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

Función de devolución de llamada de eventos: en aplicaciones prácticas, diferentes eventos deben ejecutarse con diferentes acciones, por lo que es necesario definir diferentes funciones. Por conveniencia, todos los eventos en este ejemplo usan la misma función de devolución de llamada. Función: Imprime el estado del proceso antes y después de que ocurra el evento.Si el estado cambia, llama a la función de devolución de llamada correspondiente.

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]);
 }
}

Defina una matriz de tablas de migración para cada estado:

/*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},
}; 

Implementar la función de generación de eventos:

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;
 }
}

Programa de prueba: Función:

  1. El estado inicial de la máquina de estado de inicialización es sta_origin;

  2. Cree un subproceso secundario y muestre el estado actual del proceso cada segundo;

  3. La secuencia de eventos es: evt_fork-->evt_sched-->evt_sched-->evt_wait-->evt_wake.

Los lectores pueden seguir sus propias necesidades, modificar la secuencia de eventos y observar los cambios en el estado.

C Principal

/*显示当前状态*/
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);
 
}

resultado de la operación:

Se puede ver de los resultados que:

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

La secuencia de transición de estado correspondiente a la secuencia de eventos es:

origen-->ejecutando-->owencpu-->owencpu-->sleep_int-->ejecutando

Supongo que te gusta

Origin blog.csdn.net/yx5666/article/details/127411032
Recomendado
Clasificación