青山相待

            白云相爱

            梦不到紫罗袍共黄金带

            一茅斋

            野花开

            管甚谁家兴废谁成败

            陋巷单瓢亦乐哉

            贫,气不改!

            达,志不改!

【事件驱动模型】应用消息队列和状态机改进程序流程

前言

我相信有很多像我一样的小菜朋友在纠结,写程序就像记一本流水账,偶尔用点基础数据结构改进一下程序效率,这完全看不到技术的存在,看不到成长,在下不才,愿做一个敢出头的小菜,分享一下我的体悟,欢迎各路大神来指点、敲打。

正文:我观象山多妩媚

象山本无奇,多情观之现妩媚。

对我们的程序也是这样的,同样的功能要求,大牛看来万种风情,随手拿下;小菜看来欲拒还迎, 直看得心花怒放,却总不得美人心。

比喻不是很恰当,但感觉能说明一些问题:拿到功能需求以后的建模和体系结构的认识决定了小菜无力感,这里和大家讨论一种后台程序模型以帮助大家整体把握部分后台程序。 

 以GSM网络CAP信令简化模型为例,模拟SCP网元:

  

在应用程序规模较小时,比如几百行的控制台程序,完全可以用顺序结构来实现,并且那往往是最合算的方式,状态机和面向对象一样,在较小规模应用时反而会增加程序的复杂度,但当规模继续扩大时就应该构建一个模型来实现,通常采用状态机来实现。 

状态机:记录实例的当前状态,不同状态时接受不同的事件,根据当前状态以及事件进行状态迁移,使用时需要定义初始状态与终止状态以代表实例的启动和终止。 

  针对当前实例定义FSM:

 //枚举状态

enum FSM_STATE {INIT=1, RRBE, RRBE_SEND_ERR, RRBE_SEND_WAIT, RRBE_SEND_SUC, AC, AC_SEND_ERR, AC_SEND_WAIT, AC_SEND_SUC, CONTINUE, CONTINUE_SEND_ERR, CONTINUE_SEND_WAIT, CONTINUE_SEND_SUC, ERB, ERB_WAIT, ERB_RECV, ACR, ACR_WAIT, ACR_RECV, RC_SEND, END};


//定义状态表,包含主状态和子状态

TABLE FSMTable[MAX_LEN][MAX_LEN] = {{INIT},{RRBE, RRBE_SEND_ERR, RRBE_SEND_WAIT, RRBE_SEND_SUC},{AC, AC_SEND_ERR, AC_SEND_WAIT, AC_SEND_SUC}, {CONTINUE, CONTINUE_SEND_ERR, CONTINUE_SEND_WAIT, CONTINUE_SEND_SUC}, {ERB, ERB_WAIT, ERB_RECV}, {ACR, ACR_WAIT, ACR_RECV}, {RC_SEND}, {END}};


//定义状态映射表,用于从状态映射相应的处理函数

TABLE FSM2Proc[MAX_LEN][MAX_LEN] = {...};


//状态实例,包含状态和呼叫实例

struct FSM_Instance{

FSM_STATE state;

Instance ins;

};


FSM_STATE GetFSMState(FSM_Instance* fsmins);


FSM_STATE UpdateFSM(FSM_Instance* fsmins, FSM_STATE state);


func_ptr GetMsgProcByFSM(FSM_STATE fsmstate);


//当状态为INIT时处理实例,仅接受指定的事件

FSM_STATE FSM_INIT_PROC(FSM_Instance* fsmins, MSG* msg )

{

switch(msg.type)

{

case DATA_ERROR:

DoSomeThing(...);

UpdateFSM(fsmins, RC_SEND);

break;

case TimeOut:

DoSomeThing(...);

UpdateFSM(fsmins, RC_SEND);

break;

case TC_ABORT:

DoSomeThing(...);

UpdateFSM(fsmins, RC_SEND);

break;

default:

DoNothing();

break;

}

}


//收到消息后获取当前实例状态,并映射当前状态对应的处理函数,将消息传入状态处理函数

void EventProcess(MSG* msg)

{

func_ptr func = GetMsgProcByFSM(GetFSMState(fsminstance));

func(fsminstance, msg);

}


//消息队列,事件驱动程序中必要的组成部分,在线程的初始化工作完成以后循环处理消息,并根据消息中的实例号投递给相应的实例处理,示例为简化实现

void GetSCPMsg()

{

while(GetMsg(&msg))

{

EventProcess();

}

}

  经过消息队列和状态机改装以后的程序是不是清晰很多,个人感觉这个模型的优点是结构很清晰,更容易实现子功能的低耦合、高内聚,修改起来也很容易,破坏性被局限在固定的处理过程,缺点就是实现一个完整的状态机和消息机制并不容易,使用不当反而会增加复杂度。

后记

这篇写的不尽如人意,有很多地方讲的不明不白,阐述这样一个框架对我来说也是第一次,吃力是免不了的,希望各位多指点。

posted @ 2014-06-17 12:02  Leo.Z  阅读(3594)  评论(0编辑  收藏  举报