uCos中的邮箱和消息队列
文章目录
- 1. 背景
- 2. 直接通信与间接通信
- 3. 消息机制
- 4. 消息队列
- 5. ucos-ii中实现
- 5.1. 任务创建
- 5.2. 发送消息
- 5.3. 等待消息
1. 背景
前段时间老师上课讲到了uC/OS中的邮箱和消息队列,所以我想要结合《μC/OS-III源码分析笔记》和中国大学MOOC-电子科技大学《嵌入式系统及应用》PPT写一篇笔记对这部分的内容进行总结。
2. 直接通信与间接通信
直接通信:在通信过程中双方必须明确地知道(命名)彼此。
- Send (P,message) – 发送一个消息到任务P
- Receive(Q,message) – 从任务Q接收一个消息
间接通信:通信双方不需要指出消息的来源或去向,而通过中间机 制来通信
- send(A,message) – 发送一个消息给邮箱A
- receive(A,message) – 从邮箱A接收一个消息
3. 消息机制
- 消息队列:属于间接通信方式
- 消息:内存空间中一段长度可变的缓冲区,其长度和内容均可以由用户定义和解释,其
内容可以是实际的数据、数据块的指针或空
。 - 从操作系统观点看,消息没有定义的格式,所有的消息都是字节流,没有特定的含义。
- 应用可以只把消息当成一个标志,这时消息机制用于实现同步。
- 消息:内存空间中一段长度可变的缓冲区,其长度和内容均可以由用户定义和解释,其
- 消息机制可进一步分为:邮箱和消息队列。邮箱仅能存放单条消息, 消息队列可存放若干消息。
- 消息机制可支持定长与可变长度两种模式的消息。
4. 消息队列
Figure 1. 消息队列机制的主要数据结构\text{Figure 1. 消息队列机制的主要数据结构} Figure 1. 消息队列机制的主要数据结构
- 消息队列控制块:管理所有创建的消息队列,系统运行时动态分配和 回收消息队列控制块。
- 消息队列缓冲区:存放该队列的消息内容。
- 如何进行消息的发送或接收?
完整的消息内容拷贝
or传递指针
(效率高、系统性能好、空间占用小)?
Figure 2. 消息队列的状态图\text{Figure 2. 消息队列的状态图} Figure 2. 消息队列的状态图
Figure 3. 消息队列的主要数据结构\text{Figure 3. 消息队列的主要数据结构} Figure 3. 消息队列的主要数据结构
Figure 4. 消息队列的环形缓冲\text{Figure 4. 消息队列的环形缓冲} Figure 4. 消息队列的环形缓冲
Figure 5. 接收消息流程图\text{Figure 5. 接收消息流程图} Figure 5. 接收消息流程图
Figure 6.消息队列的典型应用\text{Figure 6.消息队列的典型应用} Figure 6.消息队列的典型应用
5. ucos-ii中实现
5.1. 任务创建
OS_EVENT *OSQCreate (void **start, INT16U size)
{#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr;
#endifOS_EVENT *pevent;OS_Q *pq;if (OSIntNesting > 0) { /* See if called from ISR ... */return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */}OS_ENTER_CRITICAL();pevent = OSEventFreeList; /* Get next free event control block */if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;}OS_EXIT_CRITICAL();if (pevent != (OS_EVENT *)0) { /* See if we have an event control block */OS_ENTER_CRITICAL();pq = OSQFreeList; /* Get a free queue control block */if (pq != (OS_Q *)0) { /* Were we able to get a queue control block ? */OSQFreeList = OSQFreeList->OSQPtr; /* Yes, Adjust free list pointer to next free*/OS_EXIT_CRITICAL();pq->OSQStart = start; /* Initialize the queue */pq->OSQEnd = &start[size];pq->OSQIn = start;pq->OSQOut = start;pq->OSQSize = size;pq->OSQEntries = 0;pevent->OSEventType = OS_EVENT_TYPE_Q;pevent->OSEventCnt = 0;pevent->OSEventPtr = pq;OS_EventWaitListInit(pevent); /* Initalize the wait list */} else {pevent->OSEventPtr = (void *)OSEventFreeList; /* No, Return event control block on error */OSEventFreeList = pevent;OS_EXIT_CRITICAL();pevent = (OS_EVENT *)0;}}return (pevent);
}
5.2. 发送消息
INT8U OSQPost (OS_EVENT *pevent, void *msg)
{#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr;
#endifOS_Q *pq;#if OS_ARG_CHK_EN > 0if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */return (OS_ERR_PEVENT_NULL);}if (msg == (void *)0) { /* Make sure we are not posting a NULL pointer */return (OS_ERR_POST_NULL_PTR);}if (pevent->OSEventType != OS_EVENT_TYPE_Q) { /* Validate event block type */return (OS_ERR_EVENT_TYPE);}
#endifOS_ENTER_CRITICAL();if (pevent->OSEventGrp != 0x00) { /* See if any task pending on queue */OS_EventTaskRdy(pevent, msg, OS_STAT_Q); /* Ready highest priority task waiting on event */OS_EXIT_CRITICAL();OS_Sched(); /* Find highest priority task ready to run */return (OS_NO_ERR);}pq = (OS_Q *)pevent->OSEventPtr; /* Point to queue control block */if (pq->OSQEntries >= pq->OSQSize) { /* Make sure queue is not full */OS_EXIT_CRITICAL();return (OS_Q_FULL);}*pq->OSQIn++ = msg; /* Insert message into queue */pq->OSQEntries++; /* Update the nbr of entries in the queue */if (pq->OSQIn == pq->OSQEnd) { /* Wrap IN ptr if we are at end of queue */pq->OSQIn = pq->OSQStart;}OS_EXIT_CRITICAL();return (OS_NO_ERR);
}
5.3. 等待消息
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr;
#endifvoid *msg;OS_Q *pq;if (OSIntNesting > 0) { /* See if called from ISR ... */*err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */return ((void *)0);}
#if OS_ARG_CHK_EN > 0if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */*err = OS_ERR_PEVENT_NULL;return ((void *)0);}if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type */*err = OS_ERR_EVENT_TYPE;return ((void *)0);}
#endifOS_ENTER_CRITICAL();pq = (OS_Q *)pevent->OSEventPtr; /* Point at queue control block */if (pq->OSQEntries > 0) { /* See if any messages in the queue */msg = *pq->OSQOut++; /* Yes, extract oldest message from the queue */pq->OSQEntries--; /* Update the number of entries in the queue */if (pq->OSQOut == pq->OSQEnd) { /* Wrap OUT pointer if we are at the end of the queue */pq->OSQOut = pq->OSQStart;}OS_EXIT_CRITICAL();*err = OS_NO_ERR;return (msg); /* Return message received */}OSTCBCur->OSTCBStat |= OS_STAT_Q; /* Task will have to pend for a message to be posted */OSTCBCur->OSTCBDly = timeout; /* Load timeout into TCB */OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */OS_EXIT_CRITICAL();OS_Sched(); /* Find next highest priority task ready to run */OS_ENTER_CRITICAL();msg = OSTCBCur->OSTCBMsg;if (msg != (void *)0) { /* Did we get a message? */OSTCBCur->OSTCBMsg = (void *)0; /* Extract message from TCB (Put there by QPost) */OSTCBCur->OSTCBStat = OS_STAT_RDY;OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event */OS_EXIT_CRITICAL();*err = OS_NO_ERR;return (msg); /* Return message received */}OS_EventTO(pevent); /* Timed out */OS_EXIT_CRITICAL();*err = OS_TIMEOUT; /* Indicate a timeout occured */return ((void *)0); /* No message received */
}
联系邮箱:curren_wong@163.com
CSDN:https://me.csdn.net/qq_41729780
知乎:https://zhuanlan.zhihu.com/c_1225417532351741952
公众号:复杂网络与机器学习
欢迎关注/转载,有问题欢迎通过邮箱交流。
uCos中的邮箱和消息队列相关推荐
- FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)
我们在前面单独介绍过FreeRTOS的任务通知和消息队列, 但是在FreeRTOS中任务间的通讯还有信号量,邮箱,事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 ..增 ...
- 基础篇_06_IPC之邮箱及消息队列
邮箱和消息队列,都是在需要数据交换的场景下使用. 那么首先,先介绍邮箱.邮箱有一个具体的大小,邮箱内接收的数据的个数,不能超过邮箱总大小的四分之一. 1.邮箱的创建&消息队列的创建 /*静态邮 ...
- PHP中使用ActiveMQ实现消息队列
2019独角兽企业重金招聘Python工程师标准>>> PHP中使用ActiveMQ实现消息队列前面我们已经学了如何部署ActiveMQ, 我们知道通过ActiveMQ的一个管理后台 ...
- 面试精讲之面试考点及大厂真题 - 分布式专栏 13项目中为什么要使用消息队列
13项目中为什么要使用消息队列 学习从来无捷径,循序渐进登高峰. -- 高永祚 引言 上个章节把Redis夺命连环问掰扯完,面试还没有结束,消息队列同样是面试中必问的,分布式构建三把斧:缓存+异步+数 ...
- PHP中利用redis实现消息队列处理高并发请求思路详解
在电商活动中,常常会出现高并发的情况,例如很多人同时点击购买按钮,以至于购买人数超出了库存量,这是一种非常不理想的状况,因此,我们在PHP开发中就会引入消息队列来解决这种高并发的问题. 当用户点击按钮 ...
- ucosii事件控制块------消息邮箱与消息队列
UCOSII 使用叫做事件控制块(ECB)的数据结构来描述诸如信号量.邮箱(消息邮箱)和消息队列这些事件 #define OS_EVENT_EN (((OS_Q_EN > 0u) &&a ...
- RT-Thread 线程同步及通信 -- 信号量、互斥量、事件、邮箱、消息队列
目录 一 RT-Thread 信号量 二 RT-Thread 互斥量 三 RT-Thread 事件标志组 四 RT-Thread 邮箱 五 RT-Thread 消息队列 一 RT-Thre ...
- java 结合redis队列_在 Java 中使用 redis 的消息队列服务
前言 关于 redis 我们前面已经讨论过了缓存.分布式锁.分布式唯一标识.LBS服务的用法,这里我们来谈谈利用 redis 来实现一个消息服务. 典型的消息服务是一个生产者和消费者模式的服务.一般是 ...
- php使用redis消息队列swoole,EasySwoole中利用redis实现消息队列
什么是队列? 从数据结构上来讲,队列是一种先进先出的数据结构 什么是消息队列? 消息队列可以简单理解为:把要传输的数据放在队列中 消息队列可以分为生产者和消费者,将传输的数据放到消息队列当中,就相当于 ...
最新文章
- 信息学奥赛一本通 1309:【例1.6】回文数(Noip1999) | 洛谷 P1015 [NOIP1999 普及组] 回文数
- SQL中 Left Join 与 Right Join 与 Inner Join 与 Full Join的区别
- 多媒体台式计算机安装方法,台式机如何组装 台式机组装注意事项【详解】
- vue启动项目报错 Couldn‘t find preset “es2015“ relative to directory
- 通过PO接口表导入PO数据
- 高性能WEB开发:DOM编程
- 空间分析方法在计算机上的应用,常见的空间分析方法(很经典的总结)
- 开发工具篇——常用开发工具分享
- 为什么你该培养多维度竞争力?
- n2n内网穿透神器--可以用于设置rac搭建时的网卡(在云平台上有用)
- 【hud3966】树剖模板05
- 【FPGA的基础快速入门31-----环境光传感器】
- Android移动开发-Android设备利用光线传感器监测光照强度的实现
- ARM32 寄存器分类
- springMVC源码分析--HandlerMethod
- 【初学者知识】了解一下BASIC语言
- linux 析构函数地址获取_c语言中有析构函数吗
- 计算机基础题精选(一)
- (深度学习)构造属于你自己的Pytorch数据集
- 机械运动仿真软件测试培训,测试和机械运动测试.doc
热门文章
- 项目实训2021.07.13
- php文件后面有bak,bak文件查看器
- 2012年一个屌丝程序员的学习总结:读书、户外、泡妞、习惯、母猪产后护理...
- 星辰小队针对于软件“星遇”的第二次10天冲刺——第3天
- CANON废墨清零方法
- maven_防止在多模块Maven中找到“未找到插件”
- python将A文件夹内的所有内容原封不动复制搬运到B文件夹
- oracle大于字符串时间,Oracle
- PHP链接ctp接口,CTP接口穿透式监管升级后对外接入地址变更,适用SIMNOW 模拟账户...
- Mac 下Charles的安装和抓包