目录

1. 邮箱的原理与创建

1.1 问题概述

1.1.1 问题引入

1.1.2实现形式

1.2 设计原理

1.3 设计实现

1.3.1 定义邮箱类型

1.3.2 添加tMboxInit函数

2. 邮箱的获取与释放

2.1 设计原理

2.1.1 获取消息时缓冲区有消息

2.1.2 获取消息时缓冲区无消息

2.1.3 释放消息时等待队列有任务

2.1.4 释放消息时等待队列无任务

2.1.5 使用数组实现ring buffer

2.1.6 实现按优先级写入消息

2.2 设计实现

2.2.1 添加tMboxWait函数

2.2.2 添加tMboxNoWaitGet函数

2.2.3 添加tMboxNotify函数

3. 邮箱的清空与删除

3.1 设计原理

3.1.1 邮箱的清空

3.1.2 邮箱的删除

3.2 设计实现

3.2.1 添加tMboxFlush函数

3.2.2 添加tMboxDestroy函数

4. 邮箱的状态查询

4.1 设计实现

4.1.1 添加邮箱状态类型

4.1.2 添加tMboxGetInfo函数


1. 邮箱的原理与创建

1.1 问题概述

1.1.1 问题引入

引入邮箱机制的目的是为了实现多个任务之间的消息通信

1.1.2实现形式

邮箱机制需要满足如下需求,

① 任务A产生消息放入邮箱,由邮箱负责在任务间分发消息

② 如果邮箱中没有消息,等待消息的任务可以在邮箱上实现等待

③ 如果没有任务在邮箱上等待消息,邮箱可以先缓存接收到的消息

1.2 设计原理

设计要点如下,

① 邮箱无消息,任务在事件控制块上等待

② 邮箱没有任务等待消息,消息在ring buffer中缓存

③ 考虑到效率问题,ring buffer中只保存消息的地址,而非消息本身

说明:适用场景

此处设计的邮箱适用于2个任务之间实现消息通信,且一个固定为消息发送者,一个固定为消息接收者

1.3 设计实现

1.3.1 定义邮箱类型

// 邮箱类型
typedef struct _tMbox {// 事件控制块tEvent event;// 消息缓冲区void **msgBuffer;// 当前消息数量uint32_t count;// 最大消息数量uint32_t maxCount;// 消息缓冲区读索引uint32_t read;// 消息缓存区写索引uint32_t write;
} tMbox;

说明:关于消息缓冲区

在邮箱类型中,消息缓冲区被定义为void **类型,即对应void *类型数组,由于目前没有涉及内存管理相关内容,在实现中会定义全局的void *类型数组作为邮箱的消息缓冲区

1.3.2 添加tMboxInit函数

/*
* tMboxInit - 初始化邮箱
*/
void tMboxInit(tMbox *mbox, void **msgBuffer, uint32_t maxCount)
{tEventInit(&mbox->event, tEventTypeMbox);mbox->msgBuffer = msgBuffer;mbox->maxCount = maxCount;mbox->count = 0;mbox->read = 0;mbox->write = 0;
}

说明:tEventTypeMbox为新增的与邮箱对应的事件控制块类型

2. 邮箱的获取与释放

2.1 设计原理

2.1.1 获取消息时缓冲区有消息

处理步骤,

① 任务根据读索引获取消息

② 修改读索引,维护消息计数

2.1.2 获取消息时缓冲区无消息

处理步骤,

① 任务在事件控制块上实现等待

② 当任务被唤醒时获取消息,返回等待结果

2.1.3 释放消息时等待队列有任务

处理步骤,

① 唤醒等待队列中的队首任务,并将消息传递给该任务

2.1.4 释放消息时等待队列无任务

处理步骤,

① 根据写索引将消息加入缓冲区

② 修改写索引,维护消息计数

2.1.5 使用数组实现ring buffer

① 读索引:指向第一个可读单元

② 写索引:指向下一个可写单元

注意:需要处理下标绕回

2.1.6 实现按优先级写入消息

当写入高优先级消息时,通过反向移动读索引,并在读索引处写入实现

2.2 设计实现

2.2.1 添加tMboxWait函数

/*
* tMboxWait - 等待邮箱消息
* @msg:出参,返回邮箱消息
* return: 等待结果
*/
uint32_t tMboxWait(tMbox *mbox, void **msg, uint32_t waitTicks)
{uint32_t status = tTaskEnterCritical();if (mbox->count > 0) {// 如果有消息,则读取消息,维护索引--mbox->count;*msg = mbox->msgBuffer[mbox->read++];// 处理读下标绕回if (mbox->read >= mbox->maxCount)mbox->read = 0;tTaskExitCritical(status);return tErrorNoError;} else {// 如果没有消息,任务在事件控制块上进行等待tEventWait(&mbox->event, currentTask, (void *)0, tEventTypeMbox, waitTicks);tTaskExitCritical(status);// 当前任务进入等待,触发任务调度tTaskSched();// 当任务再次被调度运行时,取出消息,返回等待结果*msg = currentTask->eventMsg;return currentTask->waitEventResult;}
}

说明1:任务再次被调度运行,可能是,

① 消息就位,被消息唤醒

② 等待超时,被强制唤醒

此时需要tMboxWait函数的调用者根据返回值进行判断

说明2:如果任务是被消息唤醒,那么消息会被记录到task->eventMsg字段,该操作由tEventWakeUp函数实现,详见tMboxNotify函数

2.2.2 添加tMboxNoWaitGet函数

/*
* tMboxNoWaitGet - 非阻塞式获取消息
*/
uint32_t tMboxNoWaitGet(tMbox *mbox, void **msg)
{uint32_t status = tTaskEnterCritical();if (mbox->count > 0) {// 如果有消息,则读取消息,维护索引--mbox->count;*msg = mbox->msgBuffer[mbox->read++];if (mbox->read >= mbox->maxCount)mbox->read = 0;tTaskExitCritical(status);return tErrorNoError;} else {// 如果没有消息,直接返回资源不可用tTaskExitCritical(status);return tErrorResourceUnavailable;}
}

2.2.3 添加tMboxNotify函数

/*
* tMboxNotify - 释放消息
* @msg:要释放的消息地址
* @notifyOption:释放消息方式,插入头部为高优先级
*/
uint32_t tMboxNotify(tMbox *mbox, void *msg, uint32_t notifyOption)
{uint32_t status = tTaskEnterCritical();if (tEventWaitCount(&mbox->event) > 0) {// 如果有任务等待,则将消息发送给等待队列的队首任务,并将其唤醒tTask *task = tEventWakeUp(&mbox->event, msg, tErrorNoError);// 如果唤醒的任务优先级高于当前任务,则触发任务切换if (task->prio < currentTask->prio)tTaskSched();} else {// 如果没有任务等待,则将消息插入缓冲区// 首先检查缓冲区是否已满if (mbox->count >= mbox->maxCount) {tTaskExitCritical(status);return tErrorResourceFull;}// 如果缓冲区未满,根据优先级插入不同位置if (notifyOption & tMBOXSendFront) {if (mbox->read <= 0)mbox->read = mbox->maxCount - 1;else--mbox->read;mbox->msgBuffer[mbox->read] = msg;} else {mbox->msgBuffer[mbox->write++] = msg;if (mbox->write >= mbox->maxCount)mbox->write = 0;}++mbox->count;}tTaskExitCritical(status);return tErrorNoError;
}

3. 邮箱的清空与删除

3.1 设计原理

3.1.1 邮箱的清空

说明:清空邮箱就是重置消息缓冲区,无需操作等待队列

3.1.2 邮箱的删除

说明:由于目前没有涉及内存的分配与释放,因此删除邮箱时只需要将等待队列清空,消息缓冲区可不做处理

3.2 设计实现

3.2.1 添加tMboxFlush函数

/*
* tMboxFlush - 清空邮箱中的所有消息
*/
void tMboxFlush(tMbox *mbox)
{uint32_t status =tTaskEnterCritical();// 如果邮箱非空则清空所有消息if (mbox->count > 0) {mbox->read = 0;mbox->write = 0;mbox->count = 0;}tTaskExitCritical(status);
}

3.2.2 添加tMboxDestroy函数

/*
* tMboxDestroy - 销毁邮箱
*/
uint32_t tMboxDestroy(tMbox *mbox)
{uint32_t status = tTaskEnterCritical();// 移除在事件控制块上等待的所有任务// 唤醒状态为tErrorDel,msg传递为(void *)0uint32_t count = tEventRemoveAll(&mbox->event, (void *)0, tErrorDel);tTaskExitCritical(status);// 如果清空过程中有任务就绪,则触发任务切换// 因为被唤醒的任务可能优先级高于当前任务if (count > 0)tTaskSched();return count;
}

说明1:注意销毁邮箱时传递的等待结果为tErrorDel,可以据此判断tMboxWait函数的返回值,以确定任务被唤醒的原因(e.g. 资源就绪 / 延时超时 / 邮箱被删除),而不是任务被唤醒后立即进行相关资源的操作

说明2:任务调用tTaskSched的时机

① 当前任务需要进入睡眠状态时(e.g. 延时或等待资源),释放CPU

② 当前任务知道可能有优先级更高的任务可以运行时

其中第②点就体现了RTOS的实时特性

4. 邮箱的状态查询

4.1 设计实现

4.1.1 添加邮箱状态类型

// 邮箱状态类型
typedef struct _tMboxInfo {// 当前消息数量uint32_t count;// 邮箱允许的最大消息数量uint32_t maxCount;// 当前等待的任务计数uint32_t taskCount;
} tMboxInfo;

4.1.2 添加tMboxGetInfo函数

/*
* tMboxGetInfo - 查询邮箱状态
*/
void tMboxGetInfo(tMbox *mbox, tMboxInfo *info)
{uint32_t status = tTaskEnterCritical();// 拷贝邮箱状态信息info->count = mbox->count;info->maxCount = mbox->maxCount;info->taskCount = tEventWaitCount(&mbox->event);tTaskExitCritical(status);
}

RTOS原理与实现07:邮箱实现相关推荐

  1. RTOS原理及功能简介

    文章目录 1 RTOS原理及功能简介 1.1 RTOS概述 1.2 RTOS工作原理简介 1.3 RTOS如何解决前后台代码结构存在的问题 1 RTOS原理及功能简介 1.1 RTOS概述 百度百科的 ...

  2. RTOS原理与实现01:RTOS基础知识

    目录 1. 前后台系统结构 1.1 概述 1.2 前后台系统存在的问题 1.2.1 实时性不能保证 1.2.2 CPU利用率不高 1.2.3 编程思维不自然 2. RTOS原理及功能简介 2.1 概述 ...

  3. RTOS原理与实现05:事件控制块实现

    目录 1. 事件控制块的原理与创建 1.1 问题与解决方案 1.2 事件控制块原理 1.2.1 事件控制块工作流程 1.2.2 事件控制块核心功能 1.3 设计实现 1.3.1 定义事件控制块结构 1 ...

  4. RTOS原理与实现09:事件标志组实现

    目录 1. 事件标志组的原理与创建 1.1 问题概述 1.2 设计原理 1.3 设计实现 1.3.1 定义事件标志组类型 1.3.2 添加tFlagGroupInit函数 2. 事件标志组的等待与通知 ...

  5. RTOS原理与实现08:存储块实现

    目录 1. 存储块的原理与创建 1.1 问题概述 1.1.1 内存分配的需求与问题 1.1.2 固定大小内存分配方案 1.2 设计原理 1.3 设计实现 1.3.1 定义存储控制块类型 1.3.2 添 ...

  6. RTOS原理与实现06:计数信号量实现

    目录 1. 计数信号量的原理与创建 1.1 概述 1.2 设计原理 1.3 设计实现 1.3.1 定义信号量 1.3.2 添加tSemInit函数 2. 计数信号量的获取与释放 2.1 设计原理 2. ...

  7. RTOS原理与实现02:基本任务切换实现

    目录 1. 任务定义与切换原理 1.1 任务是什么 1.1.1 任务的外观 1.1.2 任务的内在 1.2 任务切换原理 1.2.1 任务切换的本质 1.2.2 要保存哪些任务运行状态 1.2.3 任 ...

  8. MCU基础以及RTOS原理知识分享

    ** 1.什么是MCU? MCU,中文简称单片机.即将CPU.存储器(RAM和ROM).多种I/O接口等集成在一片芯片上,形成的芯片级计算机.早期MCU架构多是8位为主(例如Intel 8051系列. ...

  9. RTOS原理与实现13(完):内核裁剪与移植

    目录 1. 内核裁剪 1.1 设计原理 2. Hooks扩展 2.1 设计原理 1. 内核裁剪 1.1 设计原理 所谓裁剪,即用条件编译指令控制某些代码是否编译 提供一个配置文件,用于修改裁剪相关的配 ...

最新文章

  1. 《C和C++代码精粹》——1.8 标准流
  2. Win7 下面 用easybcd 引导 安装 ubuntu 14.04
  3. MapReduce源码分析之JobSplitWriter
  4. 每日一题——leetcode237 删除链表中的结点
  5. 注意满足循环终止条件时counter是否仍在+1(记洛谷P1035WA的经历,Java语言描述)
  6. spring 安全模块在jsp中误用引起的问题
  7. 洛谷 P4390 [BOI2007]Mokia 摩基亚 解题报告
  8. 感受野,以及为什么神经网络可以分清猫是猫,狗是狗的直观理解
  9. mib节点 snmp trap_snmp trap编写
  10. Pymol教程--Caver插件 研究蛋白通道
  11. 萤火小程序商城V2.0开源版源码-支持小程序+H5+公众号+APP
  12. 用于温度测量的热敏电阻
  13. DES加密,前端示例,Java示例,在线测试
  14. 用pkg把nodejs脚本编译成跨三平台的可执行文件的经验
  15. [网络流24题] 洛谷P3356 火星探险问题 费用流
  16. Excel批量设置数字转化成“以文本形式存储的数字”
  17. springboot 启动 ApplicationContext applicationContext = null
  18. 赤壁游戏服务器获取玩家角色信息失败,赤壁进不去呀`````没服务器````
  19. 免费获取华夏邓白氏编码(021-26107504)
  20. 直播一对一视频直播聊天

热门文章

  1. sublime报错信息乱码_解决Sublime Text 3在GBK编码下的中文乱码问题
  2. 全民一起玩python课件_全民一起玩Python课基础+提高篇[免费学习]
  3. python中!ls -r_光学现象的Python实现
  4. jquery ajax实例get,jQuery中ajax的get()方法用法实例
  5. Linux中Docker常用命令
  6. Python根据正则表达式找到相应的字符串然后进行替换
  7. NFS服务安装与配置方案
  8. 鼠标悬停变小手的效果,兼容FF
  9. window10运行python弹出商店_解决 win10 命令行下运行 python 弹出 Windows 应用商店
  10. java字符串去掉html标签