第二十三章 邮箱(第一部分)
一、基本概念
邮箱可以在线程与线程之间。中断与线程之间进行消息的传递。
优点:开销更低,效率更高。
- 邮箱中的每一封邮件只能容纳固定的 4 字节内容。(STM32 是 32 位处理系统,一个指针的大小即为 4个字节,所以一封邮件恰好能够容纳一个指针)
- 当需要在线程间传递比较大的消息时,可以把指向一个缓冲区的指针作为邮件发送到邮箱中。
- 线程能够从邮箱里面读取邮件消息,当邮箱中的邮件是空时,根据用户自定义的阻塞时间决定是否挂起读取线程;当邮箱中有新邮件时,挂起的读取线程被唤醒,邮箱是一种异步的通信方式。
- 举一个简单的例子,有两个线程,线程 1 检测按键状态并发送,线程 2 读取按键状态并根据按键的状态相应地改变 LED 的亮灭。这里就可以使用邮箱的方式进行通信,线程 1 将按键的状态作为邮件发送到邮箱,线程 2 在邮箱中读取邮件获得按键状态并对 LED 执行亮灭操作。
- 这里的线程 1 也可以扩展为多个线程。例如,共有三个线程,线程 1 检测并发送按键状态,线程 2 检测并发送 ADC 采样信息,线程 3 则根据接收的信息类型不同,执行不同的操作。
邮箱特性👉
- 邮件支持先进先出方式排队与优先级排队方式,支持异步读写工作方式。
- 发送与接收邮件均支持超时机制。
- 一个线程能够从任意一个消息队列接收和发送邮件。
- 多个线程能够向同一个邮箱发送邮件和从中接收邮件。
- 邮箱中的每一封邮件只能容纳固定的 4 字节内容(可以存放地址)。
- 当队列使用结束后,需要通过删除邮箱以释放内存。
二、运作机制
线程或中断服务例程把一封 4 字节长度的邮件发送到邮箱中,而一个或多个线程可以从邮箱中接收这些邮件并进行处理。
线程或中断服务都可以给邮箱发送邮件,——————
- 非阻塞方式的邮件发送过程能够安全的应用于中断服务中,中断服务函数、定时器向线程发送消息的有效手段,
- 而阻塞方式的邮件发送只能应用于线程中
三、应用场景
-
操作系统的邮箱中可存放固定条数的邮件,邮箱容量在创建/初始化邮箱时 设定,每个邮件大小为 4字节。当需要在线程间传递比较大的消息时,可以把指向一个缓冲区的指针作为邮件发送到邮箱中。
-
与系统其它通信方式相比,邮箱的通信开销更低,效率更高,传递都是 4 个字节的邮件。
-
外其实现的发送/接收阻塞机制,能很好应用于线程与线程,中断与线程之间的通讯。
应用技巧 -
邮箱传递结构体😗
1 struct msg {
2 rt_uint8_t *data_ptr; **指向数据的指针**
3 rt_uint32_t data_size; **数据块长度的变量**
4 };
- 对结构体进行发送操作😗
1 struct msg* msg_ptr;
2 msg_ptr = (struct msg*)rt_malloc(sizeof(struct msg)); **申请结构体大小的内存空间,返回的指针指向了结构体**
3 msg_ptr->data_ptr = ...; /* 指向相应的数据块地址*/
4 msg_ptr->data_size = len; /* 数据块的长度*/
5 /* 发送这个消息指针给 mb 邮箱*/
6 rt_mb_send(mb, (rt_uint32_t)msg_ptr); :*
- 对结构体进行接收操作😗
因为收取过来的是指针,而 msg_ptr 是一个新分配出来的内存块,所以在接收线程处理完毕后,需要释放相应的内存块
1 struct msg* msg_ptr;
2 if (rt_mb_recv(mb, (rt_uint32_t*)&msg_ptr) == RT_EOK)
3 {
4 /* 在接收线程处理完毕后,需要释放相应的内存块*/
5 rt_free(msg_ptr);
6 }