LiteOS针对队列读写提供带拷贝和不带拷贝的两种方式,这两种方式在使用上有所区别,如不注意就会入坑,故此总结一下。
消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间。队列提供一部处理机制,可以起到缓存消息的作用。
队列创建
LiteOS创建队列的函数如下:
UINT32 LOS_QueueCreate(CHAR *pcQueueName,
UINT16 usLen,
UINT32 *puwQueueID,
UINT32 uwFlags,
UINT16 usMaxMsgSize);
//usLen 队列长度(消息数量),即队列可以存多少条消息
//uwFlags 队列类型 FIFO or PRIO,暂时保留未用
//usMaxMsgSize 消息最大字节数(消息长度)
注意: LOS_QueueCreate 会根据传入的队列长度、消息长度来动态申请内存空间,用于缓存用户写入队列的数据。usMaxMsgSize 队列消息的最大长度,LiteOS实际在申请空间时,会将该值再加上4,这多出来的4字节空间用于保存消息的实际长度。
UINT16 usMsgSize = usMaxMsgSize + sizeof(UINT32);
不带拷贝读写方式
不带拷贝的读写方式,本质上是将消息的地址存入消息队列中,即4字节的指针。
但是:不带拷贝的读写方式,不会保存消息的长度,即用户是无法传递不定长的消息的。这块应该是LiteOS的一个bug,原则上也是可以保存的,需要修改下源码
不带拷贝的读写函数接口如下:
UINT32 LOS_QueueWrite(UINT32 uwQueueID,
VOID *pBufferAddr,
UINT32 uwBufferSize, UINT32 uwTimeOut)
//pBufferAddr 要写入的数据起始地址
//uwBufferSize 写入长度,在不带拷贝模式下,该值在代码中被固定修改为4字节(指针长度)
//uwTimeOut 超时时间. 0表示不阻塞,最大值为 LOS_WAIT_FOREVER
UINT32 LOS_QueueRead(UINT32 uwQueueID,
VOID *pBufferAddr,
UINT32 uwBufferSize, UINT32 uwTimeOut)
//pBufferAddr 存储获取到的数据地址(读取的数据要保存的目的位置)
//uwBufferSize 缓冲区长度,大于等于创建队列时的最大消息长度,尽量传入最大值
注意: 不带拷贝的读取函数,需要传入缓存长度uwBufferSize,该值必须初始化为一个大于等于队列最大消息长度的值
带拷贝的读写方式
带拷贝的读写方式,就将指定地址的消息数据全部存入消息队列中,同时队列中也会保存消息的实际长度。
带拷贝的读写函数接口如下:
//带拷贝的写入
UINT32 LOS_QueueWriteCopy(UINT32 uwQueueID,
VOID *pBufferAddr,
UINT32 uwBufferSize,
UINT32 uwTimeOut);
//带拷贝的读取
UINT32 LOS_QueueReadCopy(UINT32 uwQueueID,
VOID *pBufferAddr,
UINT32 *puwBufferSize,
UINT32 uwTimeOut);
// pBufferAddr 缓存地址
// puwBufferSize 通过该指针返回读取到的消息长度。
// 使用前,该变量需要初始为大于等于队列最大消息长度的值(队列创建时指定)
// 该值可以理解为我们将要存储消息的缓存长度,它必须是能够放得下最大长度的消息
//读取结束后,该变量保存之际读取到的消息长度
注意: 带拷贝的读取函数,需要传入指针变量puwBufferSize,函数会通过该指针返回实际读取到的消息长度。但是该指针指向的值,在使用前必须初始化为一个大于等于队列最大消息长度的值
按照如下方式使用队列读取函数:
UINT32 rxLen = 10; //rxLen的初始必须大于队列消息最大长度
uwRet = LOS_QueueReadCopy(QueID,buffer,&rxLen,0);