完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
邮箱的工作机制 1. 理解消息邮箱 邮箱是一种简单的线程间消息传递的方式,其特点是开销较低,效率较高。邮箱中的每一封邮件可以容纳固定大小的内容(针对 32 位处理器,可容纳 4 字节内容,所以一封邮件恰好可以容纳一个指针)。 邮箱的工作示意图如下,中断服务例程或者线程把一封 4 字节长度的邮件发送到邮箱中,一个或多个线程可以从邮箱中读取这些邮件并进行处理。 在中断服务例程中,只能用非阻塞的方式发送邮件。线程中可以设定发送超时时间,以阻塞的方式发送邮件。 当一个线程向邮箱发送邮件时,如果邮箱没满,将把邮件复制到邮箱中。如果邮箱已经满了,发送线程可以设置超时时间,选择等待挂起或直接返回 -RT_EFULL 。 接收邮件过程中,当邮箱中不存在邮件且超时时间不为 0 时,邮件收取过程将变成阻塞方式。 此时,只能由线程进行邮件的收取。 2. 邮箱控制块 RT-Thread 中管理邮箱的数据结构为邮箱控制块,有结构体 struct rt_mailbox 表示。另外,rt_mailbox_t 表示的是邮箱的句柄,即指向邮箱控制块的指针。邮箱控制块结构体定义如下: rt_mailbox 对象从 rt_ipc_object 中派生,由 IPC 容器管理。结构体 rt_ipc_object 定义如下: 结构体定义中,继承关系一目了然,不再赘述。 管理邮箱 RT-Thread 邮箱相关的操作函数如下所示,包含:创建 / 初始化邮箱、发送邮件、接收邮件、删除 / 脱离邮箱。 本文只重点介绍几种常用的接口函数。 1. 创建邮箱 RT-Thread 创建一个邮箱有两种方式:动态创建、静态初始化。 动态创建一个邮箱的系统函数如下,调用这个函数创建一个邮箱时,内核会先从对象管理器中分配一个邮箱对象,然后创建一个邮箱控制块,接着对邮箱控制块进行初始化,包括邮箱缓冲区地址、邮件数目、发送邮件在邮箱中的偏移等。 在对邮箱控制块初始化期间,内核会动态分配一块内存空间用来存放消息邮件,这块内存的大小等于邮件大小(4 字节)与邮箱容量的乘积。 rt_mb_create()函数的参数,name 为邮箱名称;size 表示邮箱容量;flag 为邮箱的标志,取值为 RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO。 邮箱创建成功,则返回邮箱控制块指针;创建失败,则返回 RT_NULL。 静态方式创建邮箱需要两步:(1)定义一个邮箱控制块和一段存放邮件的缓冲区 (2)对邮箱控制块进行初始化。 邮箱控制块初始化函数接口如下: 参数 mb 为邮箱控制块的指针;name 为邮箱名称;msgpool 为邮箱缓冲区指针;size 为邮箱容量;flag 为邮箱标志,与 rt_mb_create() 相同。 这里的 size 参数指定的是邮箱的容量,即如果 msgpool 指向的缓冲区的字节数是 N,那么邮箱容量应该是 N/4 。函数rt_mb_init() 的返回值为 RT_EOK。 创建邮箱的标志变量取值有两种: RT_IPC_FLAG_FIFO,等待邮箱的线程按照先进先出的方式进行排列。 RT_IPC_FLAG_PRIO,等待邮箱的线程按照优先级的方式进行排列。 2. 发送邮件 RT-Thread 提供的发送邮件接口函数有两种:一种是无等待超时接口,一种是有等待超时。 线程或者中断服务程序可以通过邮箱给其他线程发送消息,发送邮件的函数接口如下,此函数没有等待超时参数。 参数 mb 为邮箱对象的句柄;value 为邮件内容。 发送成功,函数返回 RT_EOK;发送失败,返回 -RT_EFULL,表示邮箱已经满了。 等待方式发送邮件的函数接口如下,这个函数有等待超时参数: 此函数的参数 timeout 为发送等待超时时间,单位为系统时钟节拍。其他参数与 rt_mb_send() 相同。 如果邮箱已经满了,发送线程会根据设定的 timeout 参数等待邮箱中因为收取邮件而空出空间。若超时时间到达依然没有空出空间,则发送线程将会被唤醒并返回错误码。 返回 RT_EOK 表示发送成功;返回 -RT_ETIMEOUT 表示超时;返回 -RT_ERROR 表示发送失败。 邮件的内容可以是 32 位任意格式的数据,一个整型值或一个指向某个缓冲区的指针。可以根据自己的实际应用进行设定。 注意:在中断服务例程中发送邮件时,应该采用无等待延时的方式发送,直接使用 rt_mb_send() 或者等待超时设定为 0 的函数rt_mb_send_wait()。 3.接收邮件 线程接收邮件的函数接口如下,线程接收邮件时,需要指定接收邮件的邮箱句柄、邮件存放位置以及等待的超时时间。 参数 mb 为邮箱的句柄;value 为邮箱消息存储地址;timeout 为等待超时时间。 接收成功,则返回 RT_EOK;接收超时,则返回 -RT_ETIMEOUT;接收失败,返回 -RT_ERROR。 只有当邮箱中有邮件时,接收者才能立即取到邮件并返回 RT_EOK;否则接收线程会根据设定的超时时间,挂起在等待线程队列或者立即返回(超时时间设定为 0)。 实战演练 举例来说明邮箱操作函数的用法,代码如下。动态创建两个线程,一个线程往邮箱中发送邮件,一个线程从邮箱中收取邮件。 编译,运行结果如下: 该例程中,线程 2 发送邮件,共发送了 11 次;线程 1 接收邮件,接收到了 11 封邮件,并将邮件内容打印出来,并根据判断结束运行。 其他操作函数 对于 RT-Thread 邮箱操作来说,还有删除邮箱的函数没有介绍。可以简单了解一下。 1. 删除动态创建的邮箱 删除由 rt_mb_create() 函数创建的邮箱,可以调用如下函数: 调用此函数,可以释放邮箱控制块占用的内存资源以及邮箱缓冲区占用的内存。在删除一个邮箱对象时,应该确保该邮箱不再被使用。 在删除前会唤醒所有挂起在该邮箱上的线程,然后释放邮箱对象占用的内存块。 2. 脱离静态创建的邮箱 删除 rt_mb_init() 初始化的邮箱,可以用如下函数: 调用此函数时,首先会唤醒所有挂起在该邮箱等待队列上的线程,然后将该邮箱从内核对象管理器中脱离。 |
|
相关推荐
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
683 浏览 0 评论
AI模型部署边缘设备的奇妙之旅:如何在边缘端部署OpenCV
2521 浏览 0 评论
tms320280021 adc采样波形,为什么adc采样频率上来波形就不好了?
1314 浏览 0 评论
1915 浏览 0 评论
1494 浏览 0 评论
74900 浏览 21 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 08:03 , Processed in 0.595761 second(s), Total 66, Slave 50 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号