一种使用消息队列驱动的事件响应处理算法

一.原理讲解

主要数据类型讲解

运用的是环形缓冲队列,没有用到链表,使用数组实现

消息里面携带的信息是,处理类型(对应该使用何种接口函数处理数据),数据长度,以及数据缓存。

typedef struct _msg_event {
    unsigned int type;
    unsigned int len;
    unsigned char data[8];
} MSG_EVENT;

消息队列数据类型包含,消息数据,入栈消息序号,出栈消息序号以及支持的最大消息数量。

typedef struct _queue {
    MSG_EVENT ev[EVENTS_MAX_SIZE];
    unsigned int max_size;
    unsigned int front;
    unsigned int rear;
} QUEUE;

根据消息类型执行的接口函数数据类型,包含,处理类型以及回调函数。

typedef struct _ev_map {
    unsigned int type;
    int (*handler)(MSG_EVENT* ev, void* cookie);
} EV_MAP;
工作流程图

二.源码

源码是在windows环境下编写的应用程序,使用了多任务处理,主要是为了测试功能。可以稍微修改移植到任何平台上运行。

#include<stdio.h>
#include<time.h>
#include<windows.h>
/************消息队列处理类************/
#define EVENTS_MAX_SIZE        24

typedef struct _msg_event {
    unsigned int type;
    unsigned int len;
    unsigned char data[8];
} MSG_EVENT;

typedef struct _ev_map {
    unsigned int type;
    int (*handler)(MSG_EVENT* ev, void* cookie);
} EV_MAP;

typedef struct _queue {
    MSG_EVENT ev[EVENTS_MAX_SIZE];
    unsigned int max_size;
    unsigned int front;
    unsigned int rear;
} QUEUE;

static MSG_EVENT MSG_EV_NULL[] = {
    0, NULL, NULL
};

int qevent_init(QUEUE* que, unsigned int size)
{    
    memset(que, 0x00, sizeof(QUEUE));
    que->max_size = size;
    que->front = 0;
    que->rear = 0;
    return 0;
}

int qevent_append(QUEUE *que, MSG_EVENT* ev)
{
    if ((que->rear+1)%que->max_size == que->front) 
        return -1;    
    que->ev[que->rear].type = ev->type;
    que->ev[que->rear].len = ev->len;
    memcpy(que->ev[que->rear].data, ev->data, ev->len);    
    que->rear = (que->rear+1)%que->max_size;
    return 0;
}

int qevent_destory(QUEUE *que)
{
    if (!que) return 1;
    free(que);
    que = NULL;
    return 0;
}

MSG_EVENT* qevent_pop(QUEUE *que)
{
    static MSG_EVENT ev;
    if (que->front == que->rear) 
        return MSG_EV_NULL;
    memset(&ev, 0, sizeof(ev));
    ev.type = que->ev[que->front].type;
    ev.len = que->ev[que->front].len;
    memcpy(&ev.data, que->ev[que->front].data, que->ev[que->front].len);
    que->front = (que->front+1)%que->max_size;
    return &ev;
}

int event_init(QUEUE *qev)
{
    return qevent_init(qev, EVENTS_MAX_SIZE);
}

int event_dispatch(QUEUE* qev, MSG_EVENT* msg)
{
    if (!qev) return -1;
    return qevent_append(qev, msg);
}

MSG_EVENT* event_fetch(QUEUE* qev)
{
    if (!qev) return NULL;
    return qevent_pop(qev);
}

#define EV_INVALID           0          
#define EV_CFG                1        
#define EV_CMD                2        
#define EV_TOF_RESPOND        3        
#define EV_SYS_RESPOND        4        

int ev_cmd_cb(MSG_EVENT* ev, void* cookie)
{
    switch (ev->data[0]){
        case 1:
            printf("cmd 1 \n");
            break;
        case 2:
            printf("cmd 2 \n");
            break;
        case 3:
            printf("cmd 3 \n");
            break;
        default:
            printf("cmd 0 \n");
            break;
    }
    return 0;
}

int ev_cfg_cb(MSG_EVENT* ev, void* cookie)
{
    switch (ev->data[0]){
        case 1:
            printf("cfg 1 \n");
            break;
        case 2:
            printf("cfg 2 \n");
            break;
        case 3:
            printf("cfg 3 \n");
            break;
        default:
            printf("cfg 0 \n");
            break;
    }
    return 0;
}

int ev_tof_cb(MSG_EVENT* ev, void* cookie)
{
    switch (ev->data[0]){
        case 1:
            printf("tof 1 \n");
            break;
        case 2:
            printf("tof 2 \n");
            break;
        case 3:
            printf("tof 3 \n");
            break;
        default:
            printf("tof 0 \n");
            break;
    }
    return 0;
}

EV_MAP event_maps[] = {
    {EV_CMD,  ev_cmd_cb},
    {EV_CFG,  ev_cfg_cb},
    {EV_TOF_RESPOND, ev_tof_cb}, /* 由程序内部事件自动触发 */ 
    {EV_INVALID, NULL}
};

QUEUE qev_main;

int sr_event_init(void)
{
    int ret = 0;
    
    ret = event_init(&qev_main);
    if (ret < 0){
        return -1;
    }
    return ret;
}
int sr_event_handle(void)
{
    unsigned char i = 0;
    while (1){ 
        MSG_EVENT* ev_msg = event_fetch(&qev_main);
        if (ev_msg->type == EV_INVALID) 
            return -1;    
        for (i=0; i<sizeof(event_maps)/sizeof(EV_MAP); ++i){
            if (event_maps[i].type == ev_msg->type) {
                if (event_maps[i].handler){
                    event_maps[i].handler(ev_msg, NULL);
                }
            }
        }
    }
}
/************************************/
DWORD WINAPI ThreadFun(LPVOID pM)
{
  while(1){
       sr_event_handle();
       Sleep(100);
   }
}

DWORD WINAPI ThreadFun2(LPVOID pM)
{
  static MSG_EVENT ev = {
      .type = 1,
      .len = 1,
      .data[0] = 2,
  };

 static MSG_EVENT ev2 = {
      .type = 3,
      .len = 1,
      .data[0] = 3,
  };
  while(1){
       event_dispatch(&qev_main,&ev);
       event_dispatch(&qev_main,&ev2);
       Sleep(300);
   }
}

DWORD WINAPI ThreadFun3(LPVOID pM)
{
  static MSG_EVENT ev = {
      .type = 2,
      .len = 1,
      .data[0] = 1,
  };
  while(1){
       event_dispatch(&qev_main,&ev);
       Sleep(150);
   }
}

void create_thread(void)
{
    HANDLE handle = CreateThread(NULL,0,ThreadFun,NULL,0,NULL);
    HANDLE handle2 = CreateThread(NULL,0,ThreadFun2,NULL,0,NULL);
    HANDLE handle3 = CreateThread(NULL,0,ThreadFun3,NULL,0,NULL);
    WaitForSingleObject(handle, INFINITE);  
    WaitForSingleObject(handle2, INFINITE);
    WaitForSingleObject(handle3, INFINITE);
}
void main(void)
{
    sr_event_init();
    create_thread();
    while(1){ 
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值