文章目录

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

热门文章

  1. 修改falcon的钉钉告警格式
  2. GPM数据批量下载教程
  3. 毕业两年的大专生程序员工作总结(java后端)
  4. 文因互联CEO鲍捷:八一八聊天机器人
  5. 副驾驶的意义_副驾驶在飞行中的作用与地位
  6. 新型云基础设施项目Airship 介绍
  7. TZ环境变量,时区,夏令时
  8. 专题05-python操作微信(wxpy)
  9. 和AWS云游四海@都是为了那片碧水蓝天
  10. 高级政工师具备的能力_高端大气上档次!我也想当教授级高级政工师。