HI3861学习笔记(10)——HarmonyOS(CMSIS-RTOS2)消息队列
Posted Leung_ManWah
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HI3861学习笔记(10)——HarmonyOS(CMSIS-RTOS2)消息队列相关的知识,希望对你有一定的参考价值。
一、简介
1.1 消息队列
消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间。任务能够从队列里面读取消息,当队列中的消息是空时,挂起读取任务;当队列中有新消息,挂起的读取任务被唤醒并处理新消息。
用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放入队列,但并不立即处理它,同时队列还能起到缓冲消息作用。
LiteOS中使用队列数据结构实现任务异步通信工作,具有如下特性:
- 消息以先进先出方式排队,支持异步读写工作方式。
- 读队列和写队列都支持超时机制。
- 发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)消息。
- 一个任务能够从任意一个消息队列接收和发送消息。
- 多个任务能够从同一消息队列接收和发送消息。
- 当队列使用结束后,如果是动态申请的内存,需要通过释放内存函数回收。
1.2 消息队列的运作机制
创建队列时,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,返回队列ID。
在队列控制块中维护一个消息头节点位置Head和一个消息尾节点位置Tail来表示当前队列中消息存储情况。Head表示队列中被占用消息的起始位置。Tail表示队列中被空闲消息的起始位置。刚创建时Head和Tail均指向队列起始位置。
写队列时,根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。
读队列时,根据Head找到最先写入队列中的消息节点进行读取。
删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用,释放原队列所占的空间,对应的队列控制头置为初始状态。
二、API说明
以下任务管理接口位于 kernel/liteos_m/components/cmsis/2.0/cmsis_os2.h。
业务BUILD.gn中包含路径
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
2.1 osMessageQueueNew
功能 | 创建消息队列,不能在中断服务调用该函数 |
---|---|
函数定义 | osMessageQueueId_t osMessageQueueNew (uint32_t msg_count,uint32_t msg_size,const osMessageQueueAttr_t *attr) |
参数 | msg_count:队列中的最大消息数 msg_size:最大消息大小(以字节为单位) attr:消息队列属性;空:默认值 |
返回 | 消息队列ID |
2.2 osMessageQueuePut
功能 | 发送消息,如果参数timeout设置为0,可以从中断服务例程调用 |
---|---|
函数定义 | osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id,const void *msg_ptr,uint8_t msg_prio,uint32_t timeout) |
参数 | mq_id:由osMessageQueueNew获得的消息队列ID msg_ptr:要发送的消息 msg_prio:指优先级 timeout:超时值 |
返回 | 0 - 成功,非0 - 失败 |
2.3 osMessageQueueGet
功能 | 获取消息,如果参数timeout设置为0,可以从中断服务例程调用 |
---|---|
函数定义 | osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id,void *msg_ptr,uint8_t *msg_prio,uint32_t timeout) |
参数 | mq_id:由osMessageQueueNew获得的消息队列ID msg_ptr:指针指向队列中获取消息的缓冲区指针 msg_prio:指优先级 timeout:超时值 |
返回 | 0 - 成功,非0 - 失败 |
2.4 osMessageQueueDelete
功能 | 删除消息队列 |
---|---|
函数定义 | osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id) |
参数 | mq_id:消息队列ID |
返回 | 0 - 成功,非0 - 失败 |
三、通过消息队列进行线程之间交换消息
编译时在业务BUILD.gn中包含路径
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
]
在Message_example函数中,通过osMessageQueueNew()函数创建了消息队列ID,Thread_MsgQueue1()函数中通过osMessageQueuePut()函数向消息队列中发送消息。在Thread_MsgQueue2()函数中通过osMessageQueueGet()函数读取消息队列中的消息比打印出来。
void Thread_MsgQueue1 (void *argument)
{
(void)argument;
msg.Buf = "Hello BearPi-HM_Nano!"; // do some work...
msg.Idx = 0U;
while (1)
{
osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
osThreadYield(); // suspend thread
osDelay(100);
}
}
void Thread_MsgQueue2 (void *argument)
{
(void)argument;
osStatus_t status;
while (1) {
// Insert thread code here...
status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U); // wait for message
if (status == osOK) {
printf("Message Queue Get msg:%s\\n",msg.Buf);
}
}
}
static void Message_example (void) {
mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 100, NULL);
if (mid_MsgQueue == NULL) {
printf("Falied to create Message Queue!\\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024*10;
attr.priority = 25;
attr.name = "Thread_MsgQueue1";
if (osThreadNew(Thread_MsgQueue1, NULL, &attr) == NULL) {
printf("Falied to create Thread_MsgQueue1!\\n");
}
attr.name = "Thread_MsgQueue2";
if (osThreadNew(Thread_MsgQueue2, NULL, &attr) == NULL) {
printf("Falied to create Thread_MsgQueue2!\\n");
}
}
示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印从消息队列中获取的消息。
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
Message Queue Get msg:Hello BearPi-HM_Nano!
• 由 Leung 写于 2021 年 7 月 18 日
以上是关于HI3861学习笔记(10)——HarmonyOS(CMSIS-RTOS2)消息队列的主要内容,如果未能解决你的问题,请参考以下文章
HI3861学习笔记——HarmonyOS(CMSIS-RTOS2)互斥锁
HI3861学习笔记——HarmonyOS(CMSIS-RTOS2)信号量
HI3861学习笔记——HarmonyOS(CMSIS-RTOS2)事件管理