邮箱:介绍和基本服务
查看 RTOS Revealed 系列
邮箱在之前的文章中介绍过。它们可能是 Nucleus SE 支持的第二个最简单的任务间通信方法——仅次于信号。它们提供了一种在任务之间传递简单消息的低成本但灵活的方法。
使用邮箱
在 Nucleus SE 中,邮箱是在构建时配置的。一个应用程序最多可以配置 16 个邮箱。如果未配置邮箱,则应用程序中不包含属于邮箱的数据结构或服务调用代码。
邮箱只是一个存储位置,足够容纳 ADDR 类型的单个变量 ,对其的访问受到控制,以便多个任务可以安全地使用它。一项任务可以写入邮箱。然后它就满了,在任务读取邮箱或邮箱重置之前,没有任务可以发送给它。尝试发送到一个完整的邮箱或从一个空的邮箱中读取可能会导致错误或任务暂停,具体取决于 API 调用中选择的选项和 Nucleus SE 配置。
邮箱和队列
在某些操作系统实现中,没有实现邮箱,建议使用单项队列作为替代方案。这听起来很合理,因为这样的队列将提供与邮箱相同的功能。然而,队列是一种比邮箱更复杂的数据结构,并且在数据(头和尾指针等)、代码和执行时间方面的开销要大得多。
使用 Nucleus SE,就像 Nucleus RTOS 一样,您可以选择两种对象类型,并可以自己做出决定。
如果您的应用程序包括多个队列,但可能是单个邮箱,则值得考虑替代方法。用队列替换该邮箱会产生少量数据开销,但会消除所有与邮箱相关的 API 代码。以两种方式配置应用程序并比较内存占用和性能将非常容易。
队列将在以后的文章中讨论。
配置邮箱
邮箱数量
与 Nucleus SE 的大多数方面一样,邮箱的配置主要由 #define 控制 nuse_config.h 中的语句 .关键设置是 NUSE_MAILBOX_NUMBER ,这决定了为应用程序配置的邮箱数量。默认设置为 0(即没有邮箱在使用中),您可以将其设置为最多 16 的任何值。错误的值将导致编译时错误,这是由 nuse_config_check.h<中的测试生成的/b> (这包含在 nuse_config.c 中 因此使用此模块编译)导致 #error 正在编译的语句。
选择非零值是邮箱的“主启用”。这导致一些数据结构被相应地定义和调整大小,下一篇文章将详细介绍。它还激活 API 启用设置。
API 启用
Nucleus SE 中的每个 API 函数(服务调用)都有一个启用 #define nuse_config.h 中的符号 .对于邮箱,这些是:
NUSE_MAILBOX_SEND
NUSE_MAILBOX_RECEIVE
NUSE_MAILBOX_RESET
NUSE_MAILBOX_INFORMATION
NUSE_MAILBOX_COUNT
默认情况下,所有这些都设置为 FALSE ,从而禁用每个服务调用并禁止包含任何实现代码。要为应用程序配置邮箱,您需要选择要使用的 API 调用并将其启用符号设置为 TRUE .
这是默认 nuse_config.h 的摘录 文件。
/* 中的邮箱数 系统 - 0-16 */ #define NUSE_MAILBOX_NUMBER 0 /* 服务调用启动器:*/ #define NUSE_MAILBOX_SEND FALSE #define NUSE_MAILBOX_RECEIVE FALSE #define NUSE_MAILBOX_RESET FALSE #define NUSE_MAILBOX_INFORMATION FALSE #define NUSE_MAILBOX_COUNT FALSE
如果启用邮箱 API 功能且未配置邮箱(NUSE_Mailbox_Count() 除外),则会导致编译时错误 这总是被允许的)。如果您的代码使用未启用的 API 调用,则会导致链接时间错误,因为应用程序中不会包含任何实现代码。
邮箱服务调用
Nucleus RTOS 支持九个属于邮箱的服务调用,提供以下功能:
向邮箱发送消息。由 NUSE_Mailbox_Send() 实现 在 Nucleus SE 中。
从邮箱接收消息。由 NUSE_Mailbox_Receive() 实现 在 Nucleus SE 中。
将邮箱恢复到未使用状态,没有暂停(重置)任务。由 NUSE_Mailbox_Reset() 实现 在 Nucleus SE 中。
提供指定邮箱的信息。由 NUSE_Mailbox_Information() 实现 在 Nucleus SE 中。
返回为应用程序(当前)配置了多少邮箱的计数。由 NUSE_Mailbox_Count() 实现 在 Nucleus SE 中。
向应用程序添加一个新邮箱(创建)。未在 Nucleus SE 中实现。
从应用程序中删除邮箱(删除)。未在 Nucleus SE 中实现。
返回指向应用程序中所有邮箱(当前)的指针。未在 Nucleus SE 中实现。
向邮箱(广播)上暂停的所有任务发送消息。未在 Nucleus SE 中实现。
详细检查了每个服务调用的实现。
邮箱读写服务
可以在邮箱上执行的基本操作是向其中写入数据——有时称为发送 或发布 – 并从中读取数据 – 这也称为接收 . Nucleus RTOS 和 Nucleus SE 分别为这些操作提供了两个基本的 API 调用,这里将对其进行讨论。
写入邮箱
用于写入邮箱的 Nucleus RTOS API 调用非常灵活,如果操作无法立即完成,您可以无限期挂起或超时挂起;即您尝试写入一个完整的邮箱。 Nucleus SE 提供相同的服务,只是任务挂起是可选的,并且没有实现超时。
Nucleus RTOS 还提供了向邮箱广播的功能,但 Nucleus SE 不支持此功能。它将在未实现的 API 下描述 在下一篇文章中。
用于发送到邮箱的 Nucleus RTOS API 调用
服务调用原型:
<块引用>STATUS NU_Send_To_Mailbox(NU_MAILBOX *mailbox, VOID *message, 未签名挂起);
参数:
<块引用>邮箱 – 指向要使用的邮箱的指针
留言 – 一个指向要发送的消息的指针,它是四个 unsigned 元素
暂停 – 任务暂停规范;可能是 NU_NO_SUSPEND 或 NU_SUSPEND 或超时值
退货:
<块引用>NU_SUCCESS – 通话成功
NU_INVALID_MAILBOX – 邮箱指针无效
NU_INVALID_POINTER – 消息指针为 NULL
NU_INVALID_SUSPEND – 尝试从非任务线程挂起
NU_MAILBOX_FULL – 邮箱已满,未指定挂起
NU_TIMEOUT – 暂停指定时间后,邮箱仍然是满的
NU_MAILBOX_DELETED – 任务暂停时邮箱被删除
NU_MAILBOX_WAS_RESET – 任务暂停时邮箱被重置
用于发送到邮箱的 Nucleus SE API 调用
此 API 调用支持 Nucleus RTOS API 的关键功能。
服务调用原型:
<块引用>STATUS NUSE_Mailbox_Send(NUSE_MAILBOX 邮箱,ADDR *消息, U8 挂起);
参数:
<块引用>邮箱 – 要使用的邮箱的索引(ID)
留言 – 指向要发送的消息的指针,它是 ADDR 类型的单个变量
暂停 – 任务暂停规范;可能是 NUSE_NO_SUSPEND 或 NUSE_SUSPEND
退货:
<块引用>NUSE_SUCCESS – 通话成功
NUSE_INVALID_MAILBOX – 邮箱索引无效
NUSE_INVALID_POINTER – 消息指针为 NULL
NUSE_INVALID_SUSPEND – 尝试从非任务线程挂起或未启用阻塞 API 调用
NUSE_MAILBOX_FULL – 邮箱已满,未指定挂起
NUSE_MAILBOX_WAS_RESET – 任务暂停时邮箱被重置
邮箱发送的 Nucleus SE 实现
NUSE_Mailbox_Send() 的大部分代码 API 函数 - 参数检查后 - 由条件编译选择,取决于是否启用了对阻塞(任务挂起)API 调用的支持。我们将在此处分别查看这两种变体。
如果没有开启阻塞,这个API调用的逻辑很简单,代码不需要解释:
if (NUSE_Mailbox_Status[mailbox]) /* 邮箱已满 */{ return_value =NUSE_MAILBOX_FULL;}else /* 邮箱为空 */{ NUSE_Mailbox_Data[mailbox] =*message; NUSE_Mailbox_Status[邮箱] =TRUE; return_value =NUSE_SUCCESS;}
消息存储在 NUSE_Mailbox_Data[] 的适当元素中 以及标记为正在使用的邮箱。
启用阻塞后,代码变得更加复杂:
do{ if (!NUSE_Mailbox_Status[mailbox]) /* 邮箱为空 */ { NUSE_Mailbox_Data[mailbox] =*message; NUSE_Mailbox_Status[邮箱] =TRUE; if (NUSE_Mailbox_Blocking_Count[邮箱] !=0) { U8 索引; /* 检查一个任务是否被阻塞 */ /* 在这个邮箱 */ NUSE_Mailbox_Blocking_Count[mailbox]--; for (index=0; index一些解释可能有用:
代码包含在 do...while 中 循环,在参数 suspend 时继续 具有值 NUSE_SUSPEND .
如果邮箱为空,则存储提供的消息,并且邮箱状态更改为指示已满。检查邮箱上是否有任何任务暂停(等待接收)。如果有任何任务在等待,则唤醒第一个任务。 暂停 变量设置为 NUSE_NO_SUSPEND 并且 API 调用以 NUSE_SUCCESS 退出 .
如果邮箱已满并且挂起 设置为 NUSE_NO_SUSPEND ,API 调用以 NUSE_MAILBOX_FULL 退出 .如果暂停 已设置为 NUSE_SUSPEND ,任务暂停。返回时(即任务被唤醒时),如果返回值为 NUSE_SUCCESS ,表示任务被唤醒,因为一条消息已经被读取(而不是邮箱的重置)代码循环回到顶部。
嵌入式