多任务系统中消息通讯的设计方法

    通过消息通讯的方式,主要解决多任务系统中,业务执行的时序性问题,协调不同任务执行不同的步骤,统一节拍。多数的软件系统都是多任务系统,要求不同的任务(可以是线程,也可以是进程)运行特定的功能,各个任务间要通讯,使用消息是比较通用的的方式,有很多专业的消息中间件软体,下文描述如何进行消息通讯的设计。

一、各个任务的具体执行

       不同任务承担特定的功能,将任务分解成不同的执行状态,通过条件迁移任务状态,这是常用的任务设计方法。消息只是给任务以激励,任务收到激励后产生反应,当然消息也可以是任务迁移的条件;对应出在什么样的任务状态下,响应什么样的消息,执行什么样的动作,回应什么样的消息,任务状态有迁移到哪种状态;

 

二、通过时序图明确任务间的通讯

       在明确的各个任务后,业务流程的执行,一个执行流或数据流,需要流经不同的任务,同时又要有不同的回应,所以在时序图中可以先描述完全正常的执行流和数据流,不考虑异常的情况,减少先前设计任务间通讯过于复杂的情况,反而影响了设计。

       正常的执行流和数据流通过不同的任务进行特定的处理,其中的处理中是包含有执行的先后次序,不同任务间常用的传递方式,消息是用的比较多的一种,而且相对比较灵活。特别是对时序有要求的传输场景非常合适。

一个任务向另外一个任务发消息,也可以直接发给自己,都是由消息队列来记录下先后次序。

举个数字电视的播放节目的例子,用户按遥控器上的按键,STB的接收到键值后,UI绘制出播放的节目的台号,同时TUNER进行信号频率的锁定,信号锁定后,数据经过解复用后,输出到解码器,解码器运算解码出视频图像和声音,输出到显示屏和喇叭。

三、代码中消息的定义

       通常的做法是按模块定义,发出消息一方的模块,接收消息一方只是处理,消息可以带不同的参数,可以表示更多的含义,还可以有效避免过多的消息定义。

设计技巧

消息ID的格式: 源+目的+消息名称

源一般是指发出消息的模块或任务名称

目的一般是指接收消息的模块或任务名称

 

#define  MCONTRL       (0x01000000)

#define  TUNER           (0x02000000)

 

#define MCONTRL_TUNER_REQLOCK      (MCONTRL | TUNER | 0x000000001)

#define MCONTRL_TUENR_STOP      (MCONTRL | TUNER | 0x000000002)

 

#define TUNER_MCONTRL_ANSWER       (TUNER | MCONTRL | 0x00000001)

 

也可以采用数据结构的方式来进行描述,数据结构方式来定义扩展性要比上一种要强些,使用起来代码多些,没有上面一种使用的直观。

typedef struct msg_s

{

      int msgsource;

      int msgtarget;

      int msgindex;

      int msgtype;

      int msglen;

      int *msgbuffer;

}MSG_S;

 

 

四、多任务下消息处理代码框架

多任务下代码设计已经是经典的设计了,有各种参考代码,可以通过代码生成器生成框架代码。

void kb_callback(char keyvalue, int mode)

{

      UI_MSG_S  msginfo;

      msginfo.msgsource = MSG_KB;

      msginfo.msgtarget = MSG_UIAPP;

     

      switch(keyvalue)

      {

           case 0x01:

                 msginfo.msgindex = MSG_KB_KEY_1;

                 break;

           case 0x02:

                 msginfo.msgindex = MSG_KB_KEY_2;

                 break;

           case 0x03:

                 msginfo.msgindex = MSG_KB_KEY_3;

                 break;

           case 0x04:

                 msginfo.msgindex = MSG_KB_KEY_4;

                 break;

           case 0x05:

                 msginfo.msgindex = MSG_KB_KEY_5;

                 break;

           case 0x06:

                 msginfo.msgindex = MSG_KB_KEY_6;

                 break;

           case 0x07:

                 msginfo.msgindex = MSG_KB_KEY_7;

                 break;

           case 0x08:

                 msginfo.msgindex = MSG_KB_KEY_8;

                 break;

           /*

           add  other keyvalue

           */

           default:

                 break;

      }

      EFT_SendMsg(msgid, (char *)&msginfo, sizeof(msginfo) );

      return;

}

 

int main(void)

{

      int  msgid, serviceid, timerid;

      …

 

      AC_InitMsg();   //初始化消息队列

      AC_KBInit();

      AC_TimerInit();

      AC_ServiceInit();

     

      msgid = AC_CreateMsgQueue();

      printf("\n +++ msgid =%d +++\n", msgid);

      serviceid = AC_ServiceCreate(service_callback);   

      printf("\n +++ serviceid =%d +++\n", serviceid);

 

      AC_KBRegisterCallBack(kb_callback);

      timerid = AC_TimerCreate(timer_callback, 10);

      printf("\n +++ timerid =%d +++\n", timerid);

      AC_TimerStart(timerid);

 

      printf("\n +++ TASK START +++\n");

 

      …

     

      while(1)

      {

           ret = AC_ReceiveMsg(msgid, buffer, 1024, 0);

           if (ret <=0)

           {

                 continue;

           }

 

           UI_Proc(msgid ,buffer, ret);

      }

      return 0;

}

你可能感兴趣的:(多任务系统中消息通讯的设计方法)