LiteOS 消息队列
参考:【野火】物联网操作系统 LiteOS 开发实战指南
3 LiteOS消息队列
3.1 消息队列简介
- 消息队列是一种常用于任务间通信的数据结构
- 可以在任务与任务间、中断和任务间传递消息,实现接收来自任务或者中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己的空间
- 消息队列是一种异步的通信方式,用户在处理业务时,消息队列提供异步处理机制,允许将一个消息放入队列,但并不立即处理它
- 消息队列使用时需要包含头文件
los_queue.h
3.2 LiteOS消息队列的特点
- 消息以先进先出方式排队,支持异步读写工作方式
- 读队列和写队列都支持超时机制
- 发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)的任意类型消息
- 消息支持先进后出的方式排队,往队首发送消息(LIFO)
- 一个任务能够从任意一个消息队列接收和发送消息
- 多个任务能够从同一个消息队列接收和发送消息
- 当队列使用结束后,如果是动态申请的内存,需要通过释放内存函数回收
3.3 LiteOs消息队列的运作机制
- 创建队列时,用户根据传入的队列长度和消息节点来开辟相应的内存空间
- 队列控制块中维护消息头结点位置
usQueueHead
和一个消息尾节点位置usQueueTail
来表示消息队列的消息存储情况 - 可以将LiteOs消息队列看成一个_环形队列_
- 写队列是从
usQueueTail
所指的尾部的空闲节点写入区域,利用usReadWriteableCnt[OS_QUEUE_WRITE]
来判断是否可以写入 - 读队列是从
usQueueHead
找到最先入队列的消息节点进行读取,利用usReadWriteableCnt[OS_QUEUE_READ]
判断队列是否有消息可读取,若没有消息的队列进行读队列操作会引起任务挂起 - 删除队列根据传入的队列
ID
寻找到对应的队列,把队列状态设置为未使用,释放原队列所占空间 - LiteOs的消息队列采用两个双向链表来维护一个链表指向消息队列的头部,一个链表指向消息队列的尾尾
(stReadWriteList[QUEUE_HEAD_TAIL])
,通过访问这两个链表就能直接访问对应的消息空间,并且通过消息队列控制块 中的读写类型(usReadWriteableCnt[QUEUE_READ_WRITE])
来操作消息队列 - 消息队列的运作过程如下图所示
LiteOs消息队列运作图
消息队列读写消息图
3.4 LiteOs消息队列的传输机制
消息队列是一种FIFO线性表,也支持LIFO
消息数据传输支持值传递(拷贝)和引用传递
两种传递方式比较
消息传递方式 大小 重要性 拷贝 数据量小的场合 数据重要性高 引用方式 数据量大的场合 重要性一般场合
3.5 消息队列的阻塞机制
- 顾名思义,就是指读/写消息队列时,能够完整的不受其他任务干扰的完成读/写,即阻塞机制
3.5.1 出队阻塞
- 读操作,若消息队列中没有消息,会有三种选择
- 该任务继续干别的事情,不会进入阻塞状态
- 该任务等待消息队列的消息,等待时间由用户定制,等待过程即为阻塞状态,消息队列有了对应的消息后,该任务转为就绪状态,然后根据该任务的优先级读取队列消息,若超时,则该任务放弃等待,去干别的事情
- 该任务死等,等不到消息就不干别的事情,该任务一直进入阻塞状态,直到完成读取队列的消息
3.5.2 入队阻塞
- 写操作,若消息队列已经满了,会进行如下处理
- 发送消息操作的时候,当且仅当队列被允许入队时,发送者才能成功发送消息
- 队列中无可用消息空间时,系统会根据用户指定的阻塞超时时间将任务阻塞,在指定的超时时间内如果还不能完成入队操作,发送消息的任务或者中断服务程序会收到一个错误代码
LOS_ERRNO_QUEUE_ISFULL
,然后解除阻塞状态 - 只有在任务中发送消息才允许进行阻塞状态,在中断中发送消息不允许带有阻塞机制的,否则返回错误代码
LOS_ERRNO_QUEUE_READ_IN_INTERRUPT
- 如果有多个任务阻塞在一个消息队列中,那么这些阻塞的任务将按照任务优先级进行排序,优先级高的任务将优先获得队列的访问权
3.6 常用消息队列的函数介绍
3.6.1 使用队列模块的典型流程
- 创建消息队列
LOS_QueueCreate
,在创建任务之前 - 创建成功后,可以得到消息队列的
ID
值 - 写队列操作函数
LOS_QueueWrite
,在对应需要传递消息的任务中使用 - 读队列操作函数
LOS_QueueRead
,在对应需要读取消息的任务中使用 - 删除队列
LOS_QueueDelete
3.6.2 创建消息队列LOS_QueueCreate()
创建消息队列的内存空间:
内存空间=消息队列控制块大小+(单个消息空间大小+4字节)∗消息队列长度内存空间=消息队列控制块大小+(单个消息空间大小+4字节)*消息队列长度 内存空间=消息队列控制块大小+(单个消息空间大小+4字节)∗消息队列长度当消息队列被创建时,系统会为控制块分配对应的内存空间,用于保存消息队列的(消息存储位置,头指针,尾指针,消息大小,以及队列长度等)
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;
先定义队列
ID
,再调用LOS_QueueCreate()
函数创建,才能成功创建消息队列
3.6.2 消息队列删除函数LOS_QueueDelete()
队列删除函数是直接根据队列ID直接删除的
UINT32 LOS_QueueDelete(UINT32 uwQueueID)
队列在使用或者阻塞中是不能被删除的
3.6.3 消息队列写数据函数
任务或者中断程序都可以给消息队列写入消息
当写入消息时,
- 如果队列未满,LiteOS会将消息拷贝到消息队列的尾部,
- 若满,会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列还是满的,该任务将保持阻塞状态以等待有空闲的消息空间,如果其他任务从其等待的队列中读取了数据,则消息队列空出空间,该等待的任务自动由阻塞状态转为就绪态,并写入消息
- 当任务等待的时间超过指定的阻塞时间,即使队列中还是满的,任务也会自动从阻塞状态变为就绪态,此时发送消息的任务/中断程序会收到一个错误码:
LOS_ERRNO_QUEUE_ISFULL
不带拷贝写入函数
LOS_QueueWrite()
:UINT32 LOS_QueueWrite(UINT32 uwQueueID, // 队列IDVOID *pBufferAddr, // 存储写入的数据的起始地址UINT32 uwBufferSize, // 存入缓存区的大小UINT32 uwTimeOut); // 等待时间(0~LOS_WAIT_FOREVER)
写入队列需要注意几点:
- 在使用写入队列的操作前应先创建要写入的队列
- 在中断上下文环境中, 必须使用非阻塞模式写入,也就是等待时间为 0 个 tick
- 在初始化 LiteOS 之前无法调用此 API
- 将写入由 uwBufferSize 指定大小的数据,其数据存储在 BufferAddr 指定的地址 ,那么该数据地址必须有效,否则会发生错误
- 写入队列节点中的是数据的地址
带拷贝写入
LOS_ QueueWriteCopy()
UINT32 LOS_QueueWriteCopy(UINT32 uwQueueID, // 队列IDVOID *pBufferAddr, // 存储写入的数据的起始地址UINT32 uwBufferSize, // 存入缓存区的大小UINT32 uwTimeOut); // 等待时间(0~LOS_WAIT_FOREVER)
- 注意点同不带拷贝写入,区别是写入队列中的是存储在
pBufferAddr
中的数据
- 注意点同不带拷贝写入,区别是写入队列中的是存储在
3.6.4 消息队列读数据函数
LOS_ QueueRead()
(不带拷贝方式读出)UINT32 LOS_QueueRead(UINT32 uwQueueID, // 队列IDVOID *pBufferAddr, // 存储写入的数据的起始地址UINT32 uwBufferSize, // 存入缓存区的大小UINT32 uwTimeOut); // 等待时间(0~LOS_WAIT_FOREVER)
注意点:
- 在使用读取队列的操作前应先创建要写入的队列
- 队列读取采用的是先进先出(FIFO)模式, 首先读取首先存储在队列中的数据
- 必须要我们自己定义一个存储读取出来的数据的地方,并且把存储数据的起始地址传递给
LOS_ QueueRead()
函数,否则,将发生地址非法的错误。 - 在中断上下文环境中, 必须使用非阻塞模式写入,也就是等待时间为 0 个 tick
- 在初始化 LiteOS 之前无法调用此 API
pBufferAddr
里存放的是队列节点的地址LOS_QueueReadCopy()
和LOS_QueueWriteCopy()
是一组接口,LOS_QueueRead()
和LOS_QueueWrite()
是一组接口,两组接口需要配套使用
LOS_ QueueReadCopy()
(带拷贝读出)UINT32 LOS_QueueReadCopy(UINT32 uwQueueID, // 队列 IDVOID * pBufferAddr, // 存储获取数据的起始地址UINT32 * puwBufferSize,// 保存读取之后数据大小的值UINT32 uwTimeOut) // 等待时间
- 注意点同上,不同的是
pBufferAddr
存放的是消息队列中的数据- 需要定义一个空间保存读取数据的大小
- 注意点同上,不同的是
LiteOS 消息队列相关推荐
- LiteOS内核源码分析:消息队列Queue
本文分享自华为云社区<LiteOS内核源码分析系列十 消息队列Queue>,原文作者:zhushy . 队列(Queue)是一种常用于任务间通信的数据结构.任务能够从队列里面读取消息,当队 ...
- qt使用消息队列服务器,qt代码实现消息队列通信
qt代码实现消息队列通信 内容精选 换一换 模式介绍:命令模式(command)命令模式的解释如下:向对象发送一个请求,但是并不知道该请求的具体接收者是谁,具体的处理过程是如何的,只知道在程序运行中指 ...
- HarmonyOS IoT设备内核编程接口-----消息队列
一.概念 消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间.任务能够从队列里面读取消息,当队列中的消息是空时,挂起 ...
- Redis 笔记(04)— list类型(作为消息队列使用、在列表头部添加元素、尾部删除元素、查看列表长度、遍历指定列表区间元素、获取指定区间列表元素、阻塞式获取列表元素)
Redis 的列表是链表而不是数组.这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n). 当列表弹出了最后一个元素之后,该数据结构自动被删除, ...
- 2021年大数据Kafka(一):❤️消息队列和Kafka的基本介绍❤️
全网最详细的大数据Kafka文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 消息队列和Kafka的基本介绍 一.什么是消息队列 二.消息队列的应用场景 ...
- java多线程消息队列_java多线程消息队列的实现
1.定义一个队列缓存池: private static List queueCache = new LinkedList(); 2.定义队列缓冲池最大消息数,如果达到该值,那么队列检入将等待检出低于该 ...
- 关于创建zeromq消息队列,设置和更改IP地址,远程可以访问,不只是本地链接。python代码。
关于zeromq的创建,绑定本地,和绑定其他客户端的方法. 网上一大堆关于zmq的通信模式的介绍,包括三种类型,具体我就不在描述. 但是他们给的demo,都是创建本地作为server服务端,也作为cl ...
- Linux进程间通信(IPC)-------消息队列
消息队列是进程间通信的一种方法,他有两个操作,一个进程来发送消息(也就是向内存中写入数据),另一个是获取消息(也就是另外一个进程在内存中读取数据) 下面来看消息队列的 创建,写入,读取等需要用到的函数 ...
- 【部署类】专题:消息队列MQ、进程守护Supervisor
目录 1 背景需求 2 技术方案 2.1 消息队列 2.2 进程守护 3 源码介绍 3.1 supervisor部分 3.1.1 supervisord.conf 内容 3.1.2 MM3D.conf ...
最新文章
- Java中的executeQuery,java连接数据库executeUpdate() 和executeQuery()
- linux内核网络协议栈--网卡报文收发(十六)
- 2.10 是否要使用端到端的深度学习-深度学习第三课《结构化机器学习项目》-Stanford吴恩达教授
- ElasticSearch大数据分布式弹性搜索引擎使用—从0到1
- Oracle 原理: PL/SQL基础
- boost::serialization相关的测试程序
- android 多线程概述
- nginx与lighttpd性能简单对比
- 如何保证高可用?java删除文件夹下所有文件,技术详细介绍
- html仿真花卉代码,仿真鲜花幼儿园手工教案
- 代码审计:企业级web代码安全架构读书笔记(二)
- 可解释人工智能XAI
- 搞一下SOA | 11 SOA 系统建模
- 阿里云云计算专业认证(ACP)怎么样,怎么学习?
- 自定义拍照时 拍照界面_女研究生劝父亲盖房时把围墙退后三尺,新房成网红,一天20人拍照...
- 华为储存空间管理器可以删除吗_Cx File Explorer 免费清爽无广告的安卓手机文件管理器 (支持局域网共享/FTP/WebDAV)...
- [安卓相机1]简单小Demo
- B站 URL转16进制防止评论贴URL被屏蔽
- 记一次无意间发现某学校图书检索系统的变量覆盖漏洞
- 乐视视频”剧“好看 2016海量剧集精彩来袭
热门文章
- 2022 世界人工智能大会 论坛预告 | 让知识构建未来—知识图谱技术与应用
- Android Fragmnet-Fragment数据交换以及ListFragment的使用
- 游承超:手机防爆膜可以降低手机的压力(15P)
- 迅雷11抢先体验版,免费2T空间可离线下载高速取回
- YOLOv6: A Single-Stage Object Detection Framework for IndustrialApplications
- 怎么设置计算机自己休眠断网,win10系统怎么设置待机断网 待机断网设置方法
- 详细解读什么是自适应巡航?
- 淘宝/天猫平台商品详情API接口调用说明
- 介绍当前计算机软件应用发展状况,简要介绍我国当前税收征管软件的应用状况...
- 【深挖字符串操作】·万字总结,这些知识点你真的懂了吗?