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实现消息队列
什么是队列? 从数据结构上来讲,队列是一种先进先出的数据结构 什么是消息队列? 消息队列可以简单理解为:把要传输的数据放在队列中 消息队列可以分为生产者和消费者,将传输的数据放到消息队列当中,就相当于 ...
最新文章
- zabbix 监控 redis
- python 代码生成器 oc_iOS 移动端生成工具开发
- 命令行打印文件树列表: tree 1
- codeforces 762E(cdq分治)
- 流程图符号以及绘制流程图方法
- 服务器增加驱动器,向存储空间直通添加服务器或驱动器
- NHibernate3.0里各个dll的用处和简单说明【转】
- Atitit 计算机通信技术概要 目录 1. OSI参考模型将整个协议垂直地分为7个层次 :	1 1.1. 通信类别	2 2. 传输方式 计算机通信可分为直接式和间接式两种。	2 2.1. 1)直
- JavaScript高级程序设计第四版
- 高淇Java300集
- windows系统镜像修复计算机,Win10系统下修复Windows映像方法
- 当今主流浏览器内核简介
- 中国期货业协会——期货投教网 知识汇总
- MySQL中创建时间和更新时间的自动更新
- CSV文件如何使用EXCEL打开
- 微信小程序开发案例2---省市区信息选择
- 三、Hive数据仓库应用之Hive数据操作语言(超详细步骤指导操作,WIN10,VMware Workstation 15.5 PRO,CentOS-6.7)
- excel表格多行空白,让空白行临近上方的数据自动填充到空白行
- 爱普生连续供墨系统故障排除方法
- Sweetviz:让你只需三行代码实现Python探索性数据分析