首先我们怀着问题读代码:“进程间是如何传递大数据的?”
消息队列解决任务间大数据的传递。
消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。
消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。
队列用于任务间通信,可以实现消息的异步处理。同时消息的发送方和接收方不需要彼此联系,两者间是解耦的。(设计原则是解耦)
下面我将结合代码来分析它的几大特性:
首先来看一个基本的消息队列:
#ifndef LOSCFG_BASE_IPC_QUEUE_LIMIT
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 1024 //队列个数
#endif
LITE_OS_SEC_BSS LosQueueCB *g_allQueue = NULL;//消息队列池
LITE_OS_SEC_BSS STATIC LOS_DL_LIST g_freeQueueList;//空闲队列链表,管分配的,需要队列从这里申请
typedef struct {
UINT8 *queueHandle; /**< Pointer to a queue handle */ //指向队列句柄的指针
UINT16 queueState; /**< Queue state */ //队列状态
UINT16 queueLen; /**< Queue length */ //队列中消息总数的上限值,由创建时确定,不再改变
UINT16 queueSize; /**< Node size */ //消息节点大小,由创建时确定,不再改变,即定义了每个消息长度的上限.
UINT32 queueID; /**< queueID */ //队列ID
UINT16 queueHead; /**< Node head */ //消息头节点位置(数组下标)
UINT16 queueTail; /**< Node tail */ //消息尾节点位置(数组下标)
UINT16 readWriteableCnt[OS_QUEUE_N_RW];
//队列中可写或可读消息数,0表示可读,1表示可写
LOS_DL_LIST readWriteList[OS_QUEUE_N_RW]; /**< the linked list to be read or written, 0:readlist, 1:writelist */
//挂的都是等待读/写消息的任务链表,0表示读消息的链表,1表示写消息的任务链表
LOS_DL_LIST memList;
} LosQueueCB;//读写队列分离
具有以下特性
[√]消息以先进先出的方式排队,支持异步读写。
[√]读队列和写队列都支持超时机制。
[√]每读取一条消息,就会将该消息节点设置为空闲。
[√]发送消息类型由通信双方约定,可以允许不同长度的消息。
[√]一个任务能够从任意一个消息队列接收和发送消息。
[√]多个任务能够从同一个消息队列接收和发送消息。
[√]创建队列时所需的队列空间,默认支持接口内系统自行动态申请内存的方式,同时也支持将用户分配的队列空间作为接口入参传入的方式。
建立过程依次是:初始化队列->创建队列->任务A调用写队列接口发送消息,任务B通过读队列接口接收消息。
下面将举例分析初始化队列的过程
LITE_OS_SEC_TEXT_INIT UINT32 OsQueueInit(VOID)//消息队列模块初始化
{
LosQueueCB *queueNode = NULL;
UINT32 index;
UINT32 size;
size = LOSCFG_BASE_IPC_QUEUE_LIMIT * sizeof(LosQueueCB);//支持1024个IPC队列
/* system resident memory, don't free */
g_allQueue = (LosQueueCB *)LOS_MemAlloc(m_aucSysMem0, size);//常驻内存
if (g_allQueue == NULL) {
return LOS_ERRNO_QUEUE_NO_MEMORY;
}
(VOID)memset_s(g_allQueue, size, 0, size);//清0
LOS_ListInit(&g_freeQueueList);//初始化空闲链表
for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {//循环初始化每个消息队列
queueNode = ((LosQueueCB *)g_allQueue) + index;//一个一个来
queueNode->queueID = index;//队列的身份证
LOS_ListTailInsert(&g_freeQueueList, &queueNode->readWriteList[OS_QUEUE_WRITE]);//通过写节点挂到空闲队列链表上
}//这里要注意是用 readWriteList 挂到 g_freeQueueList链上的,要通过 GET_QUEUE_LIST 来找到 LosQueueCB
if (OsQueueDbgInitHook() != LOS_OK) {//调试队列使用的.
return LOS_ERRNO_QUEUE_NO_MEMORY;
}
return LOS_OK;
}
总结:消息队列解决任务间大数据的传递,以一种异步,解耦的方式实现任务通讯。
原作者:夏贤凤