zoukankan      html  css  js  c++  java
  • 状态机编程-队列缓冲事件,事件可异步触发

    /*根据http://www.cnblogs.com/autosar/archive/2012/06/22/2558604.html整理*/
    typedef int State; /*状态*/
    typedef int Condition;/*事件*/

    #define STATES (3 + 1) /*总共状态的数量的数量*/
    #define STATE_1 0   /*3个有效状态*/
    #define STATE_2 1
    #define STATE_3 2
    #define STATE_TRAP 3 /*陷阱状态:在陷阱状态中,不论遇到怎样的输入都不能跳出*/

    #define CONDITIONS 2  /*触发事件的数量*/
    #define CONDITION_1 0 /*2个触发输入事件*/
    #define CONDITION_2 1


    typedef void (*ActionType)(State nowstate, Condition toggleEvent);/*触发函数:现在的状态及输入*/

    typedef struct /*状态转移结构体:下一个状态,触发函数*/
    {
        State next;
        ActionType action;
    } Trasition, * pTrasition;

     

    /*根据状态转移图写出:各状态迁移结构*/

    // (s1-> c1/a1->s2)
    Trasition t1 = {
        STATE_2,
        action_1 /*st1 转移函数*/
    };

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

    /*其中的动作,由用户自己完成,在这里仅定义一条输出语句*/

    void action_1(State nowstate, Condition toggleEvent)
    {
        printf("Action 1 triggered. ");
    }

    /*最后定义跳转表:根据现在的状态和输入查找跳转动作(执行动作和下一个状态)

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

     

    /*即可表达上文中的跳转关系。
    最后定义状态机,如果不考虑多任务请求,那么状态机仅需要存储当前状态便行了。例如:*/

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

     

    /*但是考虑到当一个跳转正在进行的时候,同时又有其他任务请求跳转,则会出现数据不一致的问题。
    举个例子:task1(s1, c1/a1 –> s2)和task2(s2, c2/a2 –> s3)先后执行,是可以顺利到达s3状态的,
    但若操作a1运行的时候,执行权限被task2抢占,则task2此时看到的当前状态还是s1,s1遇到c2就进入
    陷阱状态,而不会到达s3了,也就是说,状态的跳转发生了不确定,这是不能容忍的。
    因此要重新设计状态机,增加一个“事务中”条件和一个用于存储输入的条件队列。修改后的代码如下:*/

    #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)/**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;
        State current;
        int status;
        
        if (machine->inTransaction)/*正在转移,只是将新事件添加到队列中单不发生迁移*/
        {
            push(&(machine->queue), condition);
            return STATE_INTRANSACTION;
        }
        else
        {
            machine->inTransaction = true;
            current = __step(machine, condition);
            status = poll(&(machine->queue), &next_condition);/*POLL函数的参数 &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;
    }

  • 相关阅读:
    [20190507]sga_target=0注意修改_kghdsidx_count设置.txt
    进程与线程的区别和联系
    html option选中 回显 取值
    application.properties详解 --springBoot配置文件
    Address already in use: JVM_Bind:8080错误的解决办法
    垃圾回收监视和分析
    垃圾回收器种类
    Java垃圾回收是如何工作的?
    Java垃圾回收简介
    关于堆栈的详细讲解
  • 原文地址:https://www.cnblogs.com/jieruishu/p/6774744.html
Copyright © 2011-2022 走看看