参考:【野火】物联网操作系统 LiteOS 开发实战指南

3 LiteOS消息队列

3.1 消息队列简介

  1. 消息队列是一种常用于任务间通信的数据结构
  2. 可以在任务与任务间中断和任务间传递消息,实现接收来自任务或者中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己的空间
  3. 消息队列是一种异步的通信方式,用户在处理业务时,消息队列提供异步处理机制,允许将一个消息放入队列,但并不立即处理它
  4. 消息队列使用时需要包含头文件los_queue.h

3.2 LiteOS消息队列的特点

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

3.3 LiteOs消息队列的运作机制

  1. 创建队列时,用户根据传入的队列长度消息节点来开辟相应的内存空间
  2. 队列控制块中维护消息头结点位置usQueueHead和一个消息尾节点位置usQueueTail来表示消息队列的消息存储情况
  3. 可以将LiteOs消息队列看成一个_环形队列_
  4. 写队列是从usQueueTail所指的尾部的空闲节点写入区域,利用usReadWriteableCnt[OS_QUEUE_WRITE]来判断是否可以写入
  5. 读队列是从usQueueHead找到最先入队列的消息节点进行读取,利用usReadWriteableCnt[OS_QUEUE_READ]判断队列是否有消息可读取,若没有消息的队列进行读队列操作会引起任务挂起
  6. 删除队列根据传入的队列ID寻找到对应的队列,把队列状态设置为未使用,释放原队列所占空间
  7. LiteOs的消息队列采用两个双向链表来维护一个链表指向消息队列的头部,一个链表指向消息队列的尾尾(stReadWriteList[QUEUE_HEAD_TAIL]),通过访问这两个链表就能直接访问对应的消息空间,并且通过消息队列控制块 中的读写类型(usReadWriteableCnt[QUEUE_READ_WRITE])来操作消息队列
  8. 消息队列的运作过程如下图所示

    LiteOs消息队列运作图

    消息队列读写消息图

3.4 LiteOs消息队列的传输机制

  1. 消息队列是一种FIFO线性表,也支持LIFO

  2. 消息数据传输支持值传递(拷贝)和引用传递

  3. 两种传递方式比较

    消息传递方式 大小 重要性
    拷贝 数据量小的场合 数据重要性高
    引用方式 数据量大的场合 重要性一般场合

3.5 消息队列的阻塞机制

  • 顾名思义,就是指读/写消息队列时,能够完整的不受其他任务干扰的完成读/写,即阻塞机制

3.5.1 出队阻塞

  • 读操作,若消息队列中没有消息,会有三种选择

    • 该任务继续干别的事情,不会进入阻塞状态
    • 该任务等待消息队列的消息,等待时间由用户定制,等待过程即为阻塞状态,消息队列有了对应的消息后,该任务转为就绪状态,然后根据该任务的优先级读取队列消息,若超时,则该任务放弃等待,去干别的事情
    • 该任务死等,等不到消息就不干别的事情,该任务一直进入阻塞状态,直到完成读取队列的消息

3.5.2 入队阻塞

  • 写操作,若消息队列已经满了,会进行如下处理

    • 发送消息操作的时候,当且仅当队列被允许入队时,发送者才能成功发送消息
    • 队列中无可用消息空间时,系统会根据用户指定的阻塞超时时间将任务阻塞,在指定的超时时间内如果还不能完成入队操作,发送消息的任务或者中断服务程序会收到一个错误代码LOS_ERRNO_QUEUE_ISFULL ,然后解除阻塞状态
    • 只有在任务中发送消息才允许进行阻塞状态,在中断中发送消息不允许带有阻塞机制的,否则返回错误代码LOS_ERRNO_QUEUE_READ_IN_INTERRUPT
    • 如果有多个任务阻塞在一个消息队列中,那么这些阻塞的任务将按照任务优先级进行排序,优先级高的任务将优先获得队列的访问权

3.6 常用消息队列的函数介绍

3.6.1 使用队列模块的典型流程

  1. 创建消息队列LOS_QueueCreate,在创建任务之前
  2. 创建成功后,可以得到消息队列的ID
  3. 写队列操作函数LOS_QueueWrite ,在对应需要传递消息的任务中使用
  4. 读队列操作函数LOS_QueueRead ,在对应需要读取消息的任务中使用
  5. 删除队列LOS_QueueDelete

3.6.2 创建消息队列LOS_QueueCreate()

  1. 创建消息队列的内存空间:
    内存空间=消息队列控制块大小+(单个消息空间大小+4字节)∗消息队列长度内存空间=消息队列控制块大小+(单个消息空间大小+4字节)*消息队列长度 内存空间=消息队列控制块大小+(单个消息空间大小+4字节)∗消息队列长度

  2. 当消息队列被创建时,系统会为控制块分配对应的内存空间,用于保存消息队列的(消息存储位置,头指针,尾指针,消息大小,以及队列长度等)

  3. UINT32 LOS_QueueCreate(CHAR *pcQueueName,//消息队列的名称,暂时未使用UINT16 usLen,// 队列长度UINT32 *puwQueueID,//成功创建的队列控制结构ID,需要用户在创建前定义UINT32 uwFlags,//队列参数,保留参数,暂时不使用UINT16 usMaxMsgSize )//最大消息字节
    {...
    }// 队列控制块
    typedef struct tagQueueCB
    {UINT8       *pucQueue;                              /**< 队列指针 */UINT16      usQueueState;                           /**< 队列状态 */UINT16      usQueueLen;                             /**< 队列中消息个数 */UINT16      usQueueSize;                            /**< 消息节点大小 */UINT16      usQueueID;                              /**< 队列ID */UINT16      usQueueHead;                            /**< 消息头结点位置 */UINT16      usQueueTail;                            /**< 消息尾结点位置 */UINT16      usReadWriteableCnt[2];     /**< 可读或者可写资源的计数0:可读,1:可写 */LOS_DL_LIST stReadWriteList[2];        /**< 指向要读取或写入的链表的指针0: 读列表 */LOS_DL_LIST stMemList;                              /** 指向内存链表的指针 */
    } QUEUE_CB_S;
    
  4. 先定义队列ID,再调用LOS_QueueCreate() 函数创建,才能成功创建消息队列

3.6.2 消息队列删除函数LOS_QueueDelete()

  1. 队列删除函数是直接根据队列ID直接删除的

    UINT32 LOS_QueueDelete(UINT32 uwQueueID)
    
  2. 队列在使用或者阻塞中是不能被删除的

3.6.3 消息队列写数据函数

  1. 任务或者中断程序都可以给消息队列写入消息

  2. 当写入消息时,

    • 如果队列未满,LiteOS会将消息拷贝到消息队列的尾部,
    • 若满,会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列还是满的,该任务将保持阻塞状态以等待有空闲的消息空间,如果其他任务从其等待的队列中读取了数据,则消息队列空出空间,该等待的任务自动由阻塞状态转为就绪态,并写入消息
    • 当任务等待的时间超过指定的阻塞时间,即使队列中还是满的,任务也会自动从阻塞状态变为就绪态,此时发送消息的任务/中断程序会收到一个错误码:LOS_ERRNO_QUEUE_ISFULL
  3. 不带拷贝写入函数LOS_QueueWrite()

    UINT32 LOS_QueueWrite(UINT32 uwQueueID,    // 队列IDVOID *pBufferAddr,   // 存储写入的数据的起始地址UINT32 uwBufferSize, // 存入缓存区的大小UINT32 uwTimeOut);   // 等待时间(0~LOS_WAIT_FOREVER)
    
  4. 写入队列需要注意几点:

    • 在使用写入队列的操作前应先创建要写入的队列
    • 在中断上下文环境中, 必须使用非阻塞模式写入,也就是等待时间为 0 个 tick
    • 在初始化 LiteOS 之前无法调用此 API
    • 将写入由 uwBufferSize 指定大小的数据,其数据存储在 BufferAddr 指定的地址 ,那么该数据地址必须有效,否则会发生错误
    • 写入队列节点中的是数据的地址
  5. 带拷贝写入LOS_ QueueWriteCopy()

    UINT32 LOS_QueueWriteCopy(UINT32 uwQueueID,    // 队列IDVOID *pBufferAddr,   // 存储写入的数据的起始地址UINT32 uwBufferSize, // 存入缓存区的大小UINT32 uwTimeOut);   // 等待时间(0~LOS_WAIT_FOREVER)
    
    1. 注意点同不带拷贝写入,区别是写入队列中的是存储在pBufferAddr中的数据

3.6.4 消息队列读数据函数

  1. LOS_ QueueRead()(不带拷贝方式读出)

    UINT32 LOS_QueueRead(UINT32 uwQueueID,    // 队列IDVOID *pBufferAddr,   // 存储写入的数据的起始地址UINT32 uwBufferSize, // 存入缓存区的大小UINT32 uwTimeOut);   // 等待时间(0~LOS_WAIT_FOREVER)
    
  2. 注意点:

    • 在使用读取队列的操作前应先创建要写入的队列
    • 队列读取采用的是先进先出(FIFO)模式, 首先读取首先存储在队列中的数据
    • 必须要我们自己定义一个存储读取出来的数据的地方,并且把存储数据的起始地址传递给 LOS_ QueueRead()函数,否则,将发生地址非法的错误。
    • 在中断上下文环境中, 必须使用非阻塞模式写入,也就是等待时间为 0 个 tick
    • 在初始化 LiteOS 之前无法调用此 API
    • pBufferAddr里存放的是队列节点的地址
    • LOS_QueueReadCopy()LOS_QueueWriteCopy()是一组接口,LOS_QueueRead()LOS_QueueWrite()是一组接口,两组接口需要配套使用
  3. LOS_ QueueReadCopy()(带拷贝读出)

    UINT32 LOS_QueueReadCopy(UINT32  uwQueueID,     // 队列 IDVOID *  pBufferAddr,    // 存储获取数据的起始地址UINT32 * puwBufferSize,// 保存读取之后数据大小的值UINT32  uwTimeOut)      // 等待时间
    
    1. 注意点同上,不同的是

      • pBufferAddr存放的是消息队列中的数据
      • 需要定义一个空间保存读取数据的大小

LiteOS 消息队列相关推荐

  1. LiteOS内核源码分析:消息队列Queue

    本文分享自华为云社区<LiteOS内核源码分析系列十 消息队列Queue>,原文作者:zhushy . 队列(Queue)是一种常用于任务间通信的数据结构.任务能够从队列里面读取消息,当队 ...

  2. qt使用消息队列服务器,qt代码实现消息队列通信

    qt代码实现消息队列通信 内容精选 换一换 模式介绍:命令模式(command)命令模式的解释如下:向对象发送一个请求,但是并不知道该请求的具体接收者是谁,具体的处理过程是如何的,只知道在程序运行中指 ...

  3. HarmonyOS IoT设备内核编程接口-----消息队列

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

  4. Redis 笔记(04)— list类型(作为消息队列使用、在列表头部添加元素、尾部删除元素、查看列表长度、遍历指定列表区间元素、获取指定区间列表元素、阻塞式获取列表元素)

    Redis 的列表是链表而不是数组.这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n). 当列表弹出了最后一个元素之后,该数据结构自动被删除, ...

  5. 2021年大数据Kafka(一):❤️消息队列和Kafka的基本介绍❤️

    全网最详细的大数据Kafka文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 消息队列和Kafka的基本介绍 一.什么是消息队列 二.消息队列的应用场景 ...

  6. java多线程消息队列_java多线程消息队列的实现

    1.定义一个队列缓存池: private static List queueCache = new LinkedList(); 2.定义队列缓冲池最大消息数,如果达到该值,那么队列检入将等待检出低于该 ...

  7. 关于创建zeromq消息队列,设置和更改IP地址,远程可以访问,不只是本地链接。python代码。

    关于zeromq的创建,绑定本地,和绑定其他客户端的方法. 网上一大堆关于zmq的通信模式的介绍,包括三种类型,具体我就不在描述. 但是他们给的demo,都是创建本地作为server服务端,也作为cl ...

  8. Linux进程间通信(IPC)-------消息队列

    消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据) 下面来看消息队列的 创建,写入,读取等需要用到的函数 ...

  9. 【部署类】专题:消息队列MQ、进程守护Supervisor

    目录 1 背景需求 2 技术方案 2.1 消息队列 2.2 进程守护 3 源码介绍 3.1 supervisor部分 3.1.1 supervisord.conf 内容 3.1.2 MM3D.conf ...

最新文章

  1. Java中的executeQuery,java连接数据库executeUpdate() 和executeQuery()
  2. linux内核网络协议栈--网卡报文收发(十六)
  3. 2.10 是否要使用端到端的深度学习-深度学习第三课《结构化机器学习项目》-Stanford吴恩达教授
  4. ElasticSearch大数据分布式弹性搜索引擎使用—从0到1
  5. Oracle 原理: PL/SQL基础
  6. boost::serialization相关的测试程序
  7. android 多线程概述
  8. nginx与lighttpd性能简单对比
  9. 如何保证高可用?java删除文件夹下所有文件,技术详细介绍
  10. html仿真花卉代码,仿真鲜花幼儿园手工教案
  11. 代码审计:企业级web代码安全架构读书笔记(二)
  12. 可解释人工智能XAI
  13. 搞一下SOA | 11 SOA 系统建模
  14. 阿里云云计算专业认证(ACP)怎么样,怎么学习?
  15. 自定义拍照时 拍照界面_女研究生劝父亲盖房时把围墙退后三尺,新房成网红,一天20人拍照...
  16. 华为储存空间管理器可以删除吗_Cx File Explorer 免费清爽无广告的安卓手机文件管理器 (支持局域网共享/FTP/WebDAV)...
  17. [安卓相机1]简单小Demo
  18. B站 URL转16进制防止评论贴URL被屏蔽
  19. 记一次无意间发现某学校图书检索系统的变量覆盖漏洞
  20. 乐视视频”剧“好看 2016海量剧集精彩来袭

热门文章

  1. 2022 世界人工智能大会 论坛预告 | 让知识构建未来—知识图谱技术与应用
  2. Android Fragmnet-Fragment数据交换以及ListFragment的使用
  3. 游承超:手机防爆膜可以降低手机的压力(15P)
  4. 迅雷11抢先体验版,免费2T空间可离线下载高速取回
  5. YOLOv6: A Single-Stage Object Detection Framework for IndustrialApplications
  6. 怎么设置计算机自己休眠断网,win10系统怎么设置待机断网 待机断网设置方法
  7. 详细解读什么是自适应巡航?
  8. 淘宝/天猫平台商品详情API接口调用说明
  9. 介绍当前计算机软件应用发展状况,简要介绍我国当前税收征管软件的应用状况...
  10. 【深挖字符串操作】·万字总结,这些知识点你真的懂了吗?