Fundamentos de C-11

1. Patrón de diseño de la máquina de estado

  El modo de máquina de estado es un modo de comportamiento. De hecho, es una buena manera de darse cuenta del comportamiento de conmutación de diferentes estados a través del polimorfismo. Desafortunadamente, en el entorno integrado, a veces solo se puede escribir código C puro, y se debe considerar la repetición del código. Saltos de solicitud de entrada y multitarea, etc., por lo que realmente se necesita cierta consideración para implementarlo.

    Al observar un sistema de código abierto recientemente, vi la implementación de una máquina de estado y aprendí a escribir una para compartir con ustedes.

    Primero, analice lo que necesita lograr una máquina de estado ordinaria.

    La máquina de estado almacena los cambios desde el principio hasta el presente y, en función de la entrada actual, decide el siguiente estado. Esto significa que la máquina de estado almacena el estado, recibe una entrada (lo llamamos condición de salto) y responde.

    Como se muestra en la figura anterior, {s1, s2, s3} son todos estados, y la flecha c1/a1 indica que en el estado de s1, cuando la entrada es c1, salta a s2 y realiza la operación a1.

    La parte inferior es un conjunto de entradas y la máquina de estado debería responder de la siguiente manera:

 

    Cuando un determinado estado encuentra una entrada irreconocible, entrará en el estado de trampa de forma predeterminada. En el estado de trampa, no importa qué tipo de entrada encuentre, no puede saltar.

    Para expresar los autómatas anteriores, definimos sus estados y tipos de entrada:

typedef int State;
typedef int Condition;

#define STATES 3 + 1
#define STATE_1 0
#define STATE_2 1
#define STATE_3 2
#define STATE_TRAP 3

#define CONDITIONS 2
#define CONDITION_1 0
#define CONDITION_2 1

   En el entorno integrado, debido a que el espacio de almacenamiento es relativamente pequeño, todos ellos se definen como macros. Además, para reducir la incertidumbre del tiempo de ejecución, usamos la tabla de salto O(1) para simular el salto de estado.

    Primero defina el tipo de salto:

typedef void (*ActionType)(State state, Condition condition);

typedef struct
{
    State next;
    ActionType action;
} Trasition, * pTrasition;

Luego, de acuerdo con la relación de salto en la figura anterior, defina primero tres saltos más un salto con trampa:

// (s1, c1, s2, a1)
Trasition t1 = {
    STATE_2,
    action_1
};

// (s2, c2, s3, a2)
Trasition t2 = {
    STATE_3,
    action_2
};

// (s3, c1, s2, a3)
Trasition t3 = {
    STATE_2,
    action_3
};

// (s, c, trap, a1)
Trasition tt = {
    STATE_TRAP,
    action_trap
};

    Las acciones en él son completadas por el usuario, y aquí solo se define una declaración de salida. ​​​​​​​​

void action_1(State state, Condition condition)
{
printf("Action 1 triggered.\n");
}

    Finalmente defina la tabla de salto:​​​​​​​​

pTrasition transition_table[STATES][CONDITIONS] = {
/*      c1,  c2*/
/* s1 */&t1, &tt,
/* s2 */&tt, &t2,
/* s3 */&t3, &tt,
/* st */&tt, &tt,
};

    La relación de salto anterior se puede expresar.

    Finalmente, se define la máquina de estado, si no se consideran las solicitudes multitarea, la máquina de estado solo necesita almacenar el estado actual.

    Por ejemplo:

typedef struct
{
    State current;
} StateMachine, * pStateMachine;

State step(pStateMachine machine, Condition condition)
{
    pTrasition t = transition_table[machine->current][condition];
    (*(t->action))(machine->current, condition);
    machine->current = t->next;
return machine->current;
}

    Pero teniendo en cuenta que cuando un salto está en curso, hay otras tareas que solicitan un salto al mismo tiempo, habrá un problema de inconsistencia de datos. ¿Qué software  es?  http://143ai.com

    Por ejemplo: la tarea1 (s1, c1/a1 –> s2) y la tarea2 (s2, c2/a2 –> s3) se ejecutan sucesivamente y el estado de s3 se puede alcanzar con éxito, pero si la operación a1 se está ejecutando, la ejecución El permiso está restringido por task2 Preemption, el estado actual visto por task2 en este momento sigue siendo s1, y s1 entrará en el estado de trampa cuando se encuentre con c2, y no llegará a s3. Es decir, el salto de estado es incierto, lo que no puede ser tolerado.

    Así que rediseñe la máquina de estado para agregar una condición "en transacción" y una cola de condición para almacenar entradas. El código modificado es el siguiente:

#define E_OK        0
#define E_NO_DATA   1
#define E_OVERFLOW  2

typedef struct
{
    Condition queue[QMAX];
int head;
int tail;
bool overflow;
} ConditionQueue, * pConditionQueue;


int push(ConditionQueue * queue, Condition c)
{   
unsigned int flags;
    Irq_Save(flags);
if ((queue->head == queue->tail + 1) || ((queue->head == 0) && (queue->tail == 0)))
    {
queue->overflow = true;
        Irq_Restore(flags);
return E_OVERFLOW;
    }
else
    {
queue->queue[queue->tail] = c;
queue->tail = (queue->tail + 1) % QMAX;
        Irq_Restore(flags);
    }
return E_OK;
}

int poll(ConditionQueue * queue, Condition * c)
{
unsigned int flags;
    Irq_Save(flags);
if (queue->head == queue->tail)
    {
        Irq_Restore(flags);
return E_NO_DATA;
    }
else
    {
        *c = queue->queue[queue->head];
queue->overflow = false;
queue->head = (queue->head + 1) % QMAX;
        Irq_Restore(flags);
    }
return E_OK;
}

typedef struct
{
    State current;
bool inTransaction;
    ConditionQueue queue;
} StateMachine, * pStateMachine;

static State __step(pStateMachine machine, Condition condition)
{
    State current = machine -> current;
    pTrasition t = transition_table[current][condition];
    (*(t->action))(current, condition);
    current = t->next;
    machine->current = current;
return current;
}

State step(pStateMachine machine, Condition condition)
{
    Condition next_condition;
int status;
    State current;
if (machine->inTransaction)
    {
        push(&(machine->queue), condition);
return STATE_INTRANSACTION;
    }
else
    {
        machine->inTransaction = true;
        current = __step(machine, condition);
        status = poll(&(machine->queue), &next_condition);
while(status == E_OK)
        {
            __step(machine, next_condition);
            status = poll(&(machine->queue), &next_condition);
        }
        machine->inTransaction = false;
return current;
    }
}

void initialize(pStateMachine machine, State s)
{
    machine->current = s;
    machine->inTransaction = false;
    machine->queue.head = 0;
    machine->queue.tail = 0;
    machine->queue.overflow = false;
}

Supongo que te gusta

Origin blog.csdn.net/qq_29788741/article/details/131756573
Recomendado
Clasificación