嵌入式不定长的任务消息传递组件的实现

通常如果上操作系统,这个组件便是现成的,但是很多小型系统未必都跑系统。很多软件定时器等结构也可以满足功能的模块化。不同的模块处理不同的任务,这时候任务或者是模块之间的协同、通信等就需要一套机制。下面直接上代码然后再做简要说明:


#define memory_zalloc malloc
#define memory_free free
#define memory_copy memcpy

typedef struct
{
    void *msg;
    int msgLen;
}MSG_T,*PMSG_T;

struct MsgNode
{
    MSG_T struMsg;
    struct MsgNode* next;
};

struct MsgQueue
{
    struct MsgNode* head;
    struct MsgNode* tail;
    int size; /* 当前消息数量 */
    int max;    /* 最大消息数量 */
    int dir;    /* 消息存储方向 0:尾插,1:头插 */
};

//创建一个消息队列
struct MsgQueue* creat_msg_queue(int max, int dir)
{
    struct MsgQueue* newQueue = (struct MsgQueue*)memory_zalloc(sizeof(struct MsgQueue));
    if(!newQueue) 
    {
        memory_free(newQueue);
        return 0;
    }
    newQueue->head = NULL;
    newQueue->tail = NULL;
    newQueue->size = 0;
    newQueue->max = max;
    newQueue->dir = dir ? 1 : 0;
    return newQueue;
}

//创建一条消息
static struct MsgNode* creat_msg_node(void *msg,int len)
{
    struct MsgNode* newMsgNode;
    if(!msg || !len) return 0;
    newMsgNode = (struct MsgNode*)memory_zalloc(sizeof(struct MsgNode));
    if(!newMsgNode) 
    {
        memory_free(newMsgNode);
        return 0;
    }
    newMsgNode->struMsg.msg = (void *)memory_zalloc(len+1);// 字符串最后有一个零
    if(!newMsgNode->struMsg.msg) 
    {
        memory_free(newMsgNode->struMsg.msg);
        memory_free(newMsgNode);
        return 0;
    }
    memory_copy(newMsgNode->struMsg.msg, msg,len);
    newMsgNode->struMsg.msgLen = len;
    newMsgNode->next = NULL;
    return newMsgNode;
}

//入队
int push_msg(struct MsgQueue* pMsgQueue, void *msg,int len){
 
    struct MsgNode *newMsgNode;
    if(!pMsgQueue || !msg || !len) return -1;
    if(pMsgQueue->size >= pMsgQueue->max)
    {
        printf("入队失败,队列满了!\n");
        return -2;
    }
    //创建一个新节点
    newMsgNode = creat_msg_node(msg, len);
    if(!newMsgNode) return -3;
    if(0 == pMsgQueue->size)    //队列为空
    {
        pMsgQueue->tail = pMsgQueue->head = newMsgNode;//尾指针和头指针指向本节点
    }
    else
    {
        if(pMsgQueue->dir)/* 头插 */
        {
            newMsgNode->next = pMsgQueue->head; //新节点next指向当前对头节点
            pMsgQueue->head = newMsgNode;// 对头指针指向新节点
        }
        else/* 尾插 */
        {
            pMsgQueue->tail->next = newMsgNode;//队尾结点next指向新节点
            pMsgQueue->tail = newMsgNode;//队尾指针指向新节点
        }
    }
    pMsgQueue->size++;
    return 0;
}

//出队
int pop_msg(struct MsgQueue* pMsgQueue, void** pMsg)
{
    int msgLen = 0;
    struct MsgNode* nextMsgNode;
    if(!pMsgQueue) return -1;
    
    if(0 == pMsgQueue->size)
    {
        printf("出队失败,队列为空!\n");
        return 0;
    }
    else
    {
        nextMsgNode = pMsgQueue->head->next;//定义一个指针,指向头结点的下一个结点
        msgLen = pMsgQueue->head->struMsg.msgLen;
        *pMsg = (void *)memory_zalloc(msgLen+1); // 字符串后面加0
        memset(*pMsg,0,msgLen+1);
        memory_copy(*pMsg,pMsgQueue->head->struMsg.msg,msgLen);
        memory_free(pMsgQueue->head->struMsg.msg);//释放消息空间
        memory_free(pMsgQueue->head);//释放头结点的空间
        pMsgQueue->head = nextMsgNode;//将头指针指向新的队首结点
        pMsgQueue->size--;
    }
    return msgLen;
}

// 清除所有消息
int clear_msg_queue ( struct MsgQueue* pMsgQueue )
{
    struct MsgNode* nextMsgNode;
    if ( !pMsgQueue )
    {
        return -1;
    }
    while(pMsgQueue->size)
    {
        nextMsgNode = pMsgQueue->head->next;//定义一个指针,指向头结点的下一个结点
        memory_free(pMsgQueue->head->struMsg.msg);
        memory_free(pMsgQueue->head);//释放头结点的空间
        pMsgQueue->head = nextMsgNode;//将头指针指向新的队首结点
        pMsgQueue->size--;
    }
    return 0;
}

// 释放消息
int delect_msg_queue ( struct MsgQueue* pMsgQueue )
{
    if ( !pMsgQueue )
    {
        return -1;
    }
    clear_msg_queue(pMsgQueue);
    memory_free ( pMsgQueue );
    return 0;
}

测试:代码

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
char *message[5] = 
{
    "111","2222","33333","444444","5555555",
};
void main(void *args )
{
    int i,j;
    int res;
    void *msg;
    struct MsgQueue* kkQueue;
    printf("1. create msg_queue\n");
    kkQueue = creat_msg_queue(16, 1);

    printf("2. push msg\n");

    for(j=0;j<5;j++)
        for(i=0;i<5;i++)
        {
            printf("        ");
            res = push_msg(kkQueue, message[i], strlen(message[i]));
            if(0 == res) printf("---> push msg[%s], len[%d], res[%d]\n", message[i], strlen(message[i]), res);
            else printf("\n");
        }
    
    printf("3. pop msg\n");
    for(j=0;j<5;j++)
        for(i=0;i<5;i++)
        {
            printf("        ");
            res = pop_msg(kkQueue, &msg);
            if(res >0)
            {
                printf("---> pos msg[%s], len[%d]\n", msg, res);
                memory_free(msg);
                msg = 0;
            }
        }
        
    delect_msg_queue();    
    while(1)
    {
    }
}

效果如下:

1. create msg_queue
2. push msg
        ---> push msg[111], len[3], res[0]
        ---> push msg[2222], len[4], res[0]
        ---> push msg[33333], len[5], res[0]
        ---> push msg[444444], len[6], res[0]
        ---> push msg[5555555], len[7], res[0]
        ---> push msg[111], len[3], res[0]
        ---> push msg[2222], len[4], res[0]
        ---> push msg[33333], len[5], res[0]
        ---> push msg[444444], len[6], res[0]
        ---> push msg[5555555], len[7], res[0]
        ---> push msg[111], len[3], res[0]
        ---> push msg[2222], len[4], res[0]
        ---> push msg[33333], len[5], res[0]
        ---> push msg[444444], len[6], res[0]
        ---> push msg[5555555], len[7], res[0]
        ---> push msg[111], len[3], res[0]
        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

        入队失败,队列满了!

3. pop msg
        ---> pos msg[111], len[3]
        ---> pos msg[5555555], len[7]
        ---> pos msg[444444], len[6]
        ---> pos msg[33333], len[5]
        ---> pos msg[2222], len[4]
        ---> pos msg[111], len[3]
        ---> pos msg[5555555], len[7]
        ---> pos msg[444444], len[6]
        ---> pos msg[33333], len[5]
        ---> pos msg[2222], len[4]
        ---> pos msg[111], len[3]
        ---> pos msg[5555555], len[7]
        ---> pos msg[444444], len[6]
        ---> pos msg[33333], len[5]
        ---> pos msg[2222], len[4]
        ---> pos msg[111], len[3]
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!
        出队失败,队列为空!

该方法主要采用线性表及队列结构,外加动态内存管理的方式组成。创建的时候可以选择头插法及尾插法,头插法可以理解为最新的消息优先处理。尾插法则相反,消息必须先入先出,满足队列的特性,这样可以保障先到的消息必须要按顺序一个个处理,后到的消息若空间不够则视为丢弃。

使用注意:使用pop接口获取消息后,处理完需要做内存释放动作。

By Urien 2023/02/24

你可能感兴趣的:(数据结构,单片机,数据结构)