文章目录

  • 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中的邮箱和消息队列相关推荐

  1. FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)

    我们在前面单独介绍过FreeRTOS的任务通知和消息队列, 但是在FreeRTOS中任务间的通讯还有信号量,邮箱,事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 ..增 ...

  2. 基础篇_06_IPC之邮箱及消息队列

    邮箱和消息队列,都是在需要数据交换的场景下使用. 那么首先,先介绍邮箱.邮箱有一个具体的大小,邮箱内接收的数据的个数,不能超过邮箱总大小的四分之一. 1.邮箱的创建&消息队列的创建 /*静态邮 ...

  3. PHP中使用ActiveMQ实现消息队列

    2019独角兽企业重金招聘Python工程师标准>>> PHP中使用ActiveMQ实现消息队列前面我们已经学了如何部署ActiveMQ, 我们知道通过ActiveMQ的一个管理后台 ...

  4. 面试精讲之面试考点及大厂真题 - 分布式专栏 13项目中为什么要使用消息队列

    13项目中为什么要使用消息队列 学习从来无捷径,循序渐进登高峰. -- 高永祚 引言 上个章节把Redis夺命连环问掰扯完,面试还没有结束,消息队列同样是面试中必问的,分布式构建三把斧:缓存+异步+数 ...

  5. PHP中利用redis实现消息队列处理高并发请求思路详解

    在电商活动中,常常会出现高并发的情况,例如很多人同时点击购买按钮,以至于购买人数超出了库存量,这是一种非常不理想的状况,因此,我们在PHP开发中就会引入消息队列来解决这种高并发的问题. 当用户点击按钮 ...

  6. ucosii事件控制块------消息邮箱与消息队列

    UCOSII 使用叫做事件控制块(ECB)的数据结构来描述诸如信号量.邮箱(消息邮箱)和消息队列这些事件 #define OS_EVENT_EN (((OS_Q_EN > 0u) &&a ...

  7. RT-Thread 线程同步及通信 -- 信号量、互斥量、事件、邮箱、消息队列

    目录 一  RT-Thread 信号量 二  RT-Thread 互斥量 三  RT-Thread 事件标志组 四  RT-Thread 邮箱 五  RT-Thread 消息队列 一  RT-Thre ...

  8. java 结合redis队列_在 Java 中使用 redis 的消息队列服务

    前言 关于 redis 我们前面已经讨论过了缓存.分布式锁.分布式唯一标识.LBS服务的用法,这里我们来谈谈利用 redis 来实现一个消息服务. 典型的消息服务是一个生产者和消费者模式的服务.一般是 ...

  9. php使用redis消息队列swoole,EasySwoole中利用redis实现消息队列

    什么是队列? 从数据结构上来讲,队列是一种先进先出的数据结构 什么是消息队列? 消息队列可以简单理解为:把要传输的数据放在队列中 消息队列可以分为生产者和消费者,将传输的数据放到消息队列当中,就相当于 ...

最新文章

  1. 信息学奥赛一本通 1309:【例1.6】回文数(Noip1999) | 洛谷 P1015 [NOIP1999 普及组] 回文数
  2. SQL中 Left Join 与 Right Join 与 Inner Join 与 Full Join的区别
  3. 多媒体台式计算机安装方法,台式机如何组装 台式机组装注意事项【详解】
  4. vue启动项目报错 Couldn‘t find preset “es2015“ relative to directory
  5. 通过PO接口表导入PO数据
  6. 高性能WEB开发:DOM编程
  7. 空间分析方法在计算机上的应用,常见的空间分析方法(很经典的总结)
  8. 开发工具篇——常用开发工具分享
  9. 为什么你该培养多维度竞争力?
  10. n2n内网穿透神器--可以用于设置rac搭建时的网卡(在云平台上有用)
  11. 【hud3966】树剖模板05
  12. 【FPGA的基础快速入门31-----环境光传感器】
  13. Android移动开发-Android设备利用光线传感器监测光照强度的实现
  14. ARM32 寄存器分类
  15. springMVC源码分析--HandlerMethod
  16. 【初学者知识】了解一下BASIC语言
  17. linux 析构函数地址获取_c语言中有析构函数吗
  18. 计算机基础题精选(一)
  19. (深度学习)构造属于你自己的Pytorch数据集
  20. 机械运动仿真软件测试培训,测试和机械运动测试.doc

热门文章

  1. 项目实训2021.07.13
  2. php文件后面有bak,bak文件查看器
  3. 2012年一个屌丝程序员的学习总结:读书、户外、泡妞、习惯、母猪产后护理...
  4. 星辰小队针对于软件“星遇”的第二次10天冲刺——第3天
  5. CANON废墨清零方法
  6. maven_防止在多模块Maven中找到“未找到插件”
  7. python将A文件夹内的所有内容原封不动复制搬运到B文件夹
  8. oracle大于字符串时间,Oracle
  9. PHP链接ctp接口,CTP接口穿透式监管升级后对外接入地址变更,适用SIMNOW 模拟账户...
  10. Mac 下Charles的安装和抓包