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