鸿蒙Hi3861学习十-Huawei LiteOS-M(消息队列)

一、简介

        消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间。任务能够从队列里面读取消息,当队列中的消息是空时挂起读取任务;当队列中有新消息时挂起的读取任务被唤醒并处理新消息

        用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放在队列,但并不立即处理,同时队列还能起到缓冲消息的作用

        LiteOS中使用队列数据结构实现任务异步通信工作,具有如下特性:

  • 消息以先进先出方式排队,支持异步读写工作方式
  • 读队列和写队列都支持超时机制
  • 发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)的消息。
  • 一个任务能够从任意一个消息队列接收和发送消息
  • 单个任务能够从同一个消息队列接收和发送消息
  • 当队列使用结束后,如果是动态申请的内存,需要通过释放内存函数进行内存回收。

        更多队列概念,请参考如下链接:FreeRTOS学习四(队列)_xqueuesendtobackfromisr_t_guest的博客-CSDN博客

Message Queue

二、 运作机制

        创建队列时,根据用户传入队列长度和消息节点大小来开辟相应的内存空间,以供该队列使用,返回队列ID

        在队列控制块中维护一个消息头字节位置Head和一个消息尾节点位置Tail来表示当前队列中消息存储情况。Head表示队列中被占用消息的起始位置。Tail表示队列中空闲消息的起始位置。队列刚创建时,Head和Tail均指向队列起始位置

        队列时,根据Tail找到被占用消息节点末尾的空闲节点,作为数据写入对象。

        队列时,根据Head找到最先写入队列中的消息节点进行读取。

        删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用释放原队列所占用的空间。对应的队列控制头置为初始状态。

三、API介绍

      osMessageQueueNew

        函数功能:

        创建队列。不能在中断中使用

        函数原型:

osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr)

        参数:

        msg_count:队列元素总个数

        msg_size:队列单个元素大小

        attr:属性,自定义地址时使用。默认为NULL

        返回值:

        NULL:失败

        其他:队列标识符

        实例:

typedef struct
{
  char *Buf;
  uint32_t len;
  uint32_t Idx;
} MSGQUEUE_OBJ_t;

osMessageQueueId_t mid_MsgQueue;   

mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(MSGQUEUE_OBJ_t), NULL);

      osMessageQueuePut

        函数功能:

        数据入队。如果队列满,则挂起直到队列空余或超时如果超时时间为0,可以在中断中使用

        函数原型:

osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout)

        参数:

        mq_id:队列标识符。队列创建osMessageQueueNew时获得。

        msg_ptr:入队的数据地址

        msg_prio:入队数据的优先级,优先级高,可有限被读出。

        timeout:入队超时等待时间。osWaitForever死等

        返回值:

        osOK:成功

        其他值:失败

        实例:

osMessageQueueId_t mid_MsgQueue;   

typedef struct
{
  char *Buf;
  uint32_t len;
  uint32_t Idx;
} MSGQUEUE_OBJ_t;

MSGQUEUE_OBJ_t msg;

msg.Buf = "this is a queue test";
msg.Idx = 0U;
msg.len = strlen(msg.Buf);
osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);

      osMessageQueueGet

        函数功能:

        数据出队,如果队列空,则挂起,直到队列非空或超时如果超时为0,可以在中断中调用

        函数原型:

osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout)

        参数:

        mq_id:队列标识符。队列创建osMessageQueueNew时获得。

        msg_ptr:入队的数据地址

        msg_prio:入队数据的优先级,优先级高,可有限被读出。

        timeout:入队超时等待时间。osWaitForever死等

        返回值:

        osOK:成功

        其他值:失败

        实例:

typedef struct
{
  char *Buf;
  uint32_t len;
  uint32_t Idx;
} MSGQUEUE_OBJ_t;

osMessageQueueId_t mid_MsgQueue;   
osStatus_t status;
MSGQUEUE_OBJ_t msg;

status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, osWaitForever);

      osMessageQueueGetMsgSize

        函数功能:

        获取每个队列元素的大小可以在中断中使用。

        函数原型:

uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t mq_id)

        参数:

        mq_id:队列标识符。队列创建osMessageQueueNew时获得。

        返回值:

        每个队列元素的大小

        实例:

osMessageQueueId_t mid_MsgQueue;   
osMessageQueueGetMsgSize(mid_MsgQueue);

      osMessageQueueGetCount

        函数功能:

        获取已经入队元素的个数可以在中断中调用

        函数原型:

uint32_t osMessageQueueGetCount(osMessageQueueId_t mq_id)

        参数:

        mq_id:队列标识符。队列创建osMessageQueueNew时获得。

        返回值:

        已经入队元素的个数

        实例:

osMessageQueueId_t mid_MsgQueue;   
osMessageQueueGetCount(mid_MsgQueue);

      osMessageQueueGetSpace

        函数功能:

        获取队列中空闲元素个数可以在中断中调用

        函数原型:

uint32_t osMessageQueueGetSpace(osMessageQueueId_t mq_id)

        参数:

        mq_id:队列标识符。队列创建osMessageQueueNew时获得。

        返回值:

        队列中空闲元素的个数

        实例:

osMessageQueueId_t mid_MsgQueue;   
osMessageQueueGetSpace(mid_MsgQueue);

      osMessageQueueGetCapacity

        函数功能:

        获取队列中元素总个数可以在中断中调用

        函数原型:

uint32_t osMessageQueueGetCapacity(osMessageQueueId_t mq_id)

        参数:

        mq_id:队列标识符。队列创建osMessageQueueNew时获得。

        返回值:

        队列中元素总个数

        实例:

osMessageQueueId_t mid_MsgQueue;   
osMessageQueueGetCapacity(mid_MsgQueue);

四、实例

        这里创建两个任务,一个任务操作数据入队一个任务操作数据出队。并实时监控队列状态。其中,出队的任务操作比入队慢,所以一定会队列满。

#define LOG_I(fmt, args...)   printf("<%8ld> - [QUEUE]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...)   printf("<%8ld>-[QUEUE_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);

#define MSGQUEUE_OBJECTS 16

typedef struct
{
  char *Buf;
  uint32_t len;
  uint32_t Idx;
} MSGQUEUE_OBJ_t;

osMessageQueueId_t mid_MsgQueue;   

void Thread_MsgQueue1(void *argument)
{
  (void)argument;
  MSGQUEUE_OBJ_t msg;

  static char temp_data[] = "this is a queue test";
  msg.Buf = NULL;
  msg.Idx = 0U;

  LOG_I("each element  %d Byte",osMessageQueueGetMsgSize(mid_MsgQueue));
  while (1)
  {
        msg.Buf = temp_data;
        msg.len = sizeof(temp_data);
        msg.Idx++;
        LOG_I("[enqueue]-111queued:%ld elements,left:%ld elements,total:%ld",osMessageQueueGetCount(mid_MsgQueue),osMessageQueueGetSpace(mid_MsgQueue),osMessageQueueGetCapacity(mid_MsgQueue));
        osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
        LOG_I("[enqueue]-222queued:%ld elements,left:%ld elements,total:%ld",osMessageQueueGetCount(mid_MsgQueue),osMessageQueueGetSpace(mid_MsgQueue),osMessageQueueGetCapacity(mid_MsgQueue));

        osThreadYield();
        osDelay(50);
  }
}

void Thread_MsgQueue2(void *argument)
{
  (void)argument;
  osStatus_t status;
  MSGQUEUE_OBJ_t msg;
  while (1)
  {
    LOG_I("[dequeue]-111queued:%ld elements,left:%ld elements,total:%ld",osMessageQueueGetCount(mid_MsgQueue),osMessageQueueGetSpace(mid_MsgQueue),osMessageQueueGetCapacity(mid_MsgQueue));
    status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, osWaitForever);
    LOG_I("[dequeue]-222queued:%ld elements,left:%ld elements,total:%ld",osMessageQueueGetCount(mid_MsgQueue),osMessageQueueGetSpace(mid_MsgQueue),osMessageQueueGetCapacity(mid_MsgQueue));
    if (status == osOK)
    {
       LOG_I("Message Queue Get msg:%d,len:%d-%s\n", msg.Idx,msg.len,msg.Buf);
    }
    osDelay(100);
  }
}

void app_queue_init(void)
{
    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(MSGQUEUE_OBJ_t), NULL);
    if (mid_MsgQueue == NULL)
    {
        LOG_E("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)
    {
        LOG_E("Falied to create Thread_MsgQueue1!\n");
    }
    attr.name = "Thread_MsgQueue2";
    if (osThreadNew(Thread_MsgQueue2, NULL, &attr) == NULL)
    {
        LOG_E("Falied to create Thread_MsgQueue2!\n");
    }
}

        看结果:

         可以看到,队列入队和出队正常运行,且因为入队比出队快,所以队列中空闲元素越来越少

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/19518.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国内免费cdn汇总2023最新

内容分发网络简称CDN&#xff0c;其原理大概是将网站内容分发至加速节点&#xff0c;让用户从就近的服务器节点上获取内容&#xff0c;从而提高网站的访问加载速度。大部分服务商&#xff08;如阿里云&#xff0c;腾讯云&#xff0c;京东云等&#xff09;的CDN服务是按使用量收…

【iOS】-- GET和POST(NSURLSession)

文章目录 NSURLSessionGET和POST区别 GET方法GET请求步骤 POSTPOST请求步骤 NSURLSessionDataDelegate代理方法AFNetWorking添加头文件GETPOST第一种第二种 NSURLSession 使用NSURLSession&#xff0c;一般有两步操作&#xff1a;通过NSURLSession的实例创建task&#xff1b;执…

STL配接器(容器适配器)—— stack 的介绍使用以及模拟实现。

注意 &#xff1a; 以下所有文档都来源此网站 &#xff1a; http://cplusplus.com/ 一、stack 的介绍和使用 stack 文档的介绍&#xff1a;https://cplusplus.com/reference/stack/stack/ 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&…

预训练模型之BERT、Transformer-XL、XL-Net等

文章目录 预训练模型&#xff08;Pre-trained Models, PTMs&#xff09;前置知识BERTTransformer-XLXLNetTransformer-XL类似工作&#xff08;Scalable Transformer&#xff09;1. 《Scaling Transformer to 1M tokens and beyond with RMT》2. 《》 预训练模型&#xff08;Pre…

【Linux常见指令以及权限理解】基本指令(3)

写在前面 上一篇文章&#xff0c;我们学习了Linux的一些常用指令&#xff0c; 学习了如何理解Linux系统&#xff0c;介绍了对Linux系统的理解&#xff1a;Linux下一切皆文件 介绍了重定向还有管道相关的知识。这里是上一篇博客的链接&#xff1a;http://t.csdn.cn/2d6fc 接…

Vue组件化编程

2.1. 模块与组件、模块化与组件化 模块&#xff1a; 理解&#xff1a;向外提供特定功能的 js 程序&#xff0c;一般就是一个 js 文件为什么&#xff1a;js 文件很多很复杂作用&#xff1a;复用、简化 js 的编写&#xff0c;提高 js 运行效率 组件&#xff1a; 定义&#xff…

QT界面开发杂记(五)

QString转char* QString("name").toStdString().c_str() c_str()没有‘\0’结尾可能导致一些错误可以使用以下方法解决&#xff1a; QString xmlPath "path"; const char cXmlName[1024] {0}&#xff1b; memcpy((void*)cXmlName,xmlPath.toStdStri…

Prompt learning 教学[案例篇]:文生文案例设定汇总,你可以扮演任意角色进行专业分析

Prompt learning 教学[案例篇]&#xff1a;文生文案例设定汇总&#xff0c;你可以扮演任意角色进行专业分析 1.角色扮演 行为Prompt写法“牙医”““我想让你扮演一名牙医。我会向你提供有关寻找牙科服务&#xff08;例如 X 光、清洁和其他治疗&#xff09;的个人的详细信息。…

《编程思维与实践》1072.下一位妙数

《编程思维与实践》1072.下一位妙数 题目 思路 思路与最小不重复数基本一致,从最高位开始找到第一个出现9的位置,让其加1,后面全变为0即可. 只需要再加一个判定条件:不能被9整除. 由数学知识,一个数不能被9整除当且仅当各位数之和不能被9整除. 这里给出简单的证明: 不妨以三位…

工程化:vite4和vue3里面的命令式loading的封装及使用

用习惯了vue的组件使用方式,转到vue3里面发现没有了vue的原型,不能全局挂载方法了,我们要使用命令式调用组件该怎么做, 效果展示 代码演练 1.组件结构 2.基础的组件模板loading.vue <template><sectionclass="full-loading":class

多台电脑共享鼠标键盘软件

背景 最近接手了2个不同base的项目&#xff0c;由于2个base的不同代码加密管理&#xff0c;必须要用两台电脑进行分别开发。于是&#xff0c;我不大的办公桌上要摆上2个键盘和2个鼠标&#xff0c;一下子就显得桌面特别杂乱&#xff0c;办公心情都不舒畅了。 我跟朋友吐槽了这件…

华硕ROG|玩家国度魔霸新锐2023 Windows11原厂预装系统 工厂模式恢复安装带ASUSRecevory一键还原

华硕ROG|玩家国度魔霸新锐2023 Windows11原厂预装系统 工厂模式恢复安装带ASUSRecevory一键还原 文件地址&#xff1a;https://pan.baidu.com/s/1snKOsH3OMl3GZLqeAf-GLA?pwd8888 华硕工厂恢复系统 &#xff0c;安装结束后带隐藏分区以及机器所有驱动软件 需准备一个16G左右…

《小钊记》项目启动前期工作相关记录:VUE、powerdesigner建模、虚拟机密码重置、代码生成

目录 VUE镜像基本命令vue 不是内部或外部命令路径配置路由 powerdesigner 建模栏位添加注释id设置自增导出sql 虚拟机root密码重置&#xff08;centos7&#xff09;生成代码工具安装EasyCode插件连接数据库生成代码可以自定义模板复制现有的模板&#xff0c;在其基础上进行改造…

神秘的IP地址8.8.8.8地址到底是什么?为什么会被用作DNS服务器地址呢?

当我们在配置网络连接或者路由器时&#xff0c;经常会遇到需要填写DNS服务器地址的情况。而在这些情况下&#xff0c;很多人都会听到一个神秘的数字地址&#xff1a;8.8.8.8。那么&#xff0c;这个地址到底是什么&#xff0c;为什么会被用作DNS服务器地址呢&#xff1f;本文将详…

【HA】HomeAssistant 添加 小米温湿度计2代

本方法只是被动的获取小米温湿度计广播出的温度和湿度数据&#xff0c;并没有其他更多功能。 0. 本人配置 树莓派3B Debian 11 (Bullseye) 64 位 Supervisor 2023.05.dev0901 HomeAssistant 已安装 HACS 1. 安装 打开侧边栏中的HACS&#xff0c;点击“集成” 右下角找到“…

如何把软件从C盘移到D盘?

​为什么要把软件从C盘移到D盘&#xff1f; C盘是安装操作系统的系统分区。虽然很多用户在安装系统的时候会给C盘分配了大量的磁盘空间&#xff0c;但是大多数用户会发现C盘很快就会无缘无故的被占满。这是为什么呢&#xff1f;这主要是由于大多数三方程序默认安装在C盘造成…

ios打包ipa的四种实用方法(.app转.ipa)

总结一下&#xff0c;目前.app包转为.ipa包的方法有以下几种&#xff1a; 1、Apple推荐的方式&#xff0c;即实用xcode的archive功能 Xcode菜单栏->Product->Archive->三选一&#xff0c;一般选后两个。 局限性&#xff1a;个人开发一般采用这种方法&#xff0c;但…

【C++】-const对象及成员函数之类和对象中篇完结(中)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 ❤️‍&#x1fa79;作者宣言&#xff1a;认真写好每一篇博客 &#x1f4a8;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 文章目录 前言一、案例的引入二、const对象和成员函数三、取地…

HR怎么看待PMP证书呢?

我们可以先了解一下各个公司对于PMP证书的一个观点 针对PMP证书&#xff0c;在HR看来&#xff0c;有这几个直观的感受和判断&#xff1a; 公司要求PMP优先&#xff0c;那我盯着这个看就行&#xff0c;没有就不要&#xff0c;省事儿招的多了也有一些基本了解&#xff0c;考到这…

从C语言到C++⑨(第三章_CC++内存管理)详解new和delete+面试题笔试题

目录 1. C语言动态内存管理 1.1 C/C内存分布 1.2 C语言中动态内存管理的方式 2. C动态内存管理方式 2.1 new/delete操作内置类型 2.2 初始化new数组的问题 2.3 new 和 delete 操作自定义类型 3. operator new与operator delete函数详解 3.1 operator new与operator de…
最新文章