推荐星级:
  • 1
  • 2
  • 3
  • 4
  • 5

RT-Thread快速入门-消息邮箱

更新时间:2023-10-03 07:06:26 大小:297K 上传用户:sun2152查看TA发布的资源 标签:RT-Thread 下载积分:1分 评价赚积分 (如何评价?) 打赏 收藏 评论(0) 举报

资料介绍

前 面 几 篇 文 章 介 绍 了 线 程( 任 务 )间 的 同 步 机 制 :信 号 量 、互 斥 量 、 事 件 集 。 接 下 来 我 们 学 习 线 程 ( 任 务 ) 之 间 的 通 信 机 制 。 一 般 来 说 ,RTOS 均 会 提 供 两 种 线 程 间 通 信 的 机 制 :消 息 邮 箱 和 消 息 队 列 。 RT-Thread 同 样 如 此 。 本 篇 文 章 介 绍 RT-Thread 消 息 邮 箱 相 关 的 内 容 。 邮 箱 的 工 作 机 制 1. 理 解 消 息 邮 箱 邮 箱 是 一 种 简 单 的 线 程 间 消 息 传 递 的 方 式 ,其 特 点 是 开 销 较 低 ,效 率 较 高 。 邮 箱 中 的 每 一 封 邮 件 可 以 容 纳 固 定 大 小 的 内 容 ( 针 对 32 位 处 理 器 , 可 容 纳 4 字 节 内 容 , 所 以 一 封 邮 件 恰 好 可 以 容 纳 一 个 指 针 ) 。 邮 箱 的 工 作 示 意 图 如 下 , 中 断 服 务 例 程 或 者 线 程 把 一 封 4 字 节 长 度 的 邮 件 发 送 到 邮 箱 中 ,一 个 或 多 个 线 程 可 以 从 邮 箱 中 读 取 这 些 邮 件 并 进 行 处 理 。 在 中 断 服 务 例 程 中 ,只 能 用 非 阻 塞 的 方 式 发 送 邮 件 。线 程 中 可 以 设 定 发 送 超 时 时 间 , 以 阻 塞 的 方 式 发 送 邮 件 。 当 一 个 线 程 向 邮 箱 发 送 邮 件 时 ,如 果 邮 箱 没 满 ,将 把 邮 件 复 制 到 邮 箱 中 。如 果 邮 箱 已 经 满 了 ,发 送 线 程 可 以 设 置 超 时 时 间 ,选 择 等 待 挂 起 或 直 接 返 回 -RT_EFULL 。 接 收 邮 件 过 程 中 , 当 邮 箱 中 不 存 在 邮 件 且 超 时 时 间 不 为 0 时 , 邮 件 收 取 过 程 将 变 成 阻 塞 方 式 。 此 时 , 只 能 由 线 程 进 行 邮 件 的 收 取 。 2. 邮 箱 控 制 块 RT-Thread 中 管 理 邮 箱 的 数 据 结 构 为 邮 箱 控 制 块 ,有 结 构 体 struc t rt_mai lbox 表 示 。 另 外 , rt_mai lbox_t 表 示 的 是 邮 箱 的 句 柄 , 即 指 向 邮 箱 控 制 块 的 指 针 。 邮 箱 控 制 块 结 构 体 定 义 如 下 : struct rt_mailbox { struct rt_ipc_object parent; /* 继承自 ipc_object 类 */ rt_ubase_t *msg_pool; /* 邮箱缓冲区的开始地址 */ rt_uint16_t size; /* 邮箱缓冲区的大小 */ rt_uint16_t entry; /* 邮箱中邮件的数目 */ rt_uint16_t in_offset; /* 邮件进入邮箱的偏移指针 */ rt_uint16_t out_offset; /* 邮件出邮箱的偏移指针 */ rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队列 */ }; typedef struct rt_mailbox *rt_mailbox_t; rt_mai lbox 对 象 从 rt_ipc_object 中 派 生 , 由 IPC 容 器 管 理 。 结 构 体 rt_ipc_objec t 定 义 如 下 : struct rt_object { char name[RT_NAME_MAX]; /* 内核对象名称 */ rt_uint8_t type; /* 内核对象类型 */ rt_uint8_t flag; /* 内核对象的参数 */ #ifdef RT_USING_MODULE void *module_id; /* 应用程序模块 ID */ #endif rt_list_t list; /* 内核对象管理链表 */ }; struct rt_ipc_object { struct rt_object parent; /* 继承自 rt_object */ rt_list_t suspend_thread; /* 挂起的线程链表 */ }; 结 构 体 定 义 中 , 继 承 关 系 一 目 了 然 , 不 再 赘 述 。 管 理 邮 箱 RT-Thread 邮 箱 相 关 的 操 作 函 数 如 下 所 示 , 包 含 : 创 建 / 初 始 化 邮 箱 、 发 送 邮 件 、 接 收 邮 件 、 删 除 / 脱 离 邮 箱 。 本 文 只 重 点 介 绍 几 种 常 用 的 接 口 函 数 。 1. 创 建 邮 箱 RT-Thread 创 建 一 个 邮 箱 有 两 种 方 式 : 动 态 创 建 、 静 态 初 始 化 。 动 态 创 建 一 个 邮 箱 的 系 统 函 数 如 下 ,调 用 这 个 函 数 创 建 一 个 邮 箱 时 , 内 核 会 先 从 对 象 管 理 器 中 分 配 一 个 邮 箱 对 象 ,然 后 创 建 一 个 邮 箱 控 制 块 ,接 着 对 邮 箱 控 制 块 进 行 初 始 化 ,包 括 邮 箱 缓 冲 区 地 址 、邮 件 数 目 、 发 送 邮 件 在 邮 箱 中 的 偏 移 等 。 rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag) 在 对 邮 箱 控 制 块 初 始 化 期 间 ,内 核 会 动 态 分 配 一 块 内 存 空 间 用 来 存 放 消 息 邮 件 ,这 块 内 存 的 大 小 等 于 邮 件 大 小( 4 字 节 )与 邮 箱 容 量 的 乘 积 。 rt_mb_c reate()函 数 的 参 数 , name 为 邮 箱 名 称 ; si ze 表 示 邮 箱 容 量 ; flag 为 邮 箱 的 标 志 , 取 值 为 RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO。 邮 箱 创 建 成 功 ,则 返 回 邮 箱 控 制 块 指 针 ;创 建 失 败 ,则 返 回 RT_NULL。 静 态 方 式 创 建 邮 箱 需 要 两 步 : ( 1) 定 义 一 个 邮 箱 控 制 块 和 一 段 存 放 邮 件 的 缓 冲 区 ( 2) 对 邮 箱 控 制 块 进 行 初 始 化 。 邮 箱 控 制 块 初 始 化 函 数 接 口 如 下 : rt_err_t rt_mb_init(rt_mailbox_t mb, const char* name, void* msgpool, rt_size_t size, rt_uint8_t flag) 参 数 mb 为 邮 箱 控 制 块 的 指 针 ; name 为 邮 箱 名 称 ; msgpool 为 邮 箱 缓 冲 区 指 针 ;si ze 为 邮 箱 容 量 ;flag 为 邮 箱 标 志 ,与 rt_mb_c reate() 相 同 。 这 里 的 si ze 参 数 指 定 的 是 邮 箱 的 容 量 ,即 如 果 msgpool 指 向 的 缓 冲 区 的 字 节 数 是 N, 那 么 邮 箱 容 量 应 该 是 N/4。 函 数 rt_mb_init() 的 返 回 值 为 RT_EOK。 创 建 邮 箱 的 标 志 变 量 取 值 有 两 种 :  RT_IPC_FLAG_FIFO,等 待 邮 箱 的 线 程 按 照 先 进 先 出 的 方 式 进 行 排 列 。   RT_IPC_FLAG_PRIO, 等 待 邮 箱 的 线 程 按 照 优 先 级 的 方 式 进 行 排 列 。  2. 发 送 邮 件 RT-Thread 提 供 的 发 送 邮 件 接 口 函 数 有 两 种 : 一 种 是 无 等 待 超 时 接 口 , 一 种 是 有 等 待 超 时 。 线 程 或 者 中 断 服 务 程 序 可 以 通 过 邮 箱 给 其 他 线 程 发 送 消 息 ,发 送 邮 件 的 函 数 接 口 如 下 , 此 函 数 没 有 等 待 超 时 参 数 。 rt_err_t rt_mb_send (rt_mailbox_t mb, rt_ubase_t value) 参 数 mb 为 邮 箱 对 象 的 句 柄 ; value 为 邮 件 内 容 。 发 送 成 功 , 函 数 返 回 RT_EOK; 发 送 失 败 , 返 回 -RT_EFULL, 表 示 邮 箱 已 经 满 了 。 等 待 方 式 发 送 邮 件 的 函 数 接 口 如 下 , 这 个 函 数 有 等 待 超 时 参 数 : rt_err_t rt_mb_send_wait (rt_mailbox_t mb, rt_ubase_t value, rt_int32_t timeout) 此 函 数 的 参 数 timeout 为 发 送 等 待 超 时 时 间 ,单 位 为 系 统 时 钟 节 拍 。 其 他 参 数 与 rt_mb_send() 相 同 。 如 果 邮 箱 已 经 满 了 , 发 送 线 程 会 根 据 设 定 的 timeout 参 数 等 待 邮 箱 中 因 为 收 取 邮 件 而 空 出 空 间 。 若 超 时 时 间 到 达 依 然 没 有 空 出 空 间 , 则 发 送 线 程 将 会 被 唤 醒 并 返 回 错 误 码 。 返 回 RT_EOK 表 示 发 送 成 功 ; 返 回 -RT_ETIMEOUT 表 示 超 时 ; 返 回 -RT_ERROR 表 示 发 送 失 败 。 邮 件 的 内 容 可 以 是 32 位 任 意 格 式 的 数 据 ,一 个 整 型 值 或 一 个 指 向 某 个 缓 冲 区 的 指 针 。 可 以 根 据 自 己 的 实 际 应 用 进 行 设 定 。 注 意 :在 中 断 服 务 例 程 中 发 送 邮 件 时 ,应 该 采 用 无 等 待 延 时 的 方 式 发 送 , 直 接 使 用 rt_mb_send() 或 者 等 待 超 时 设 定 为 0 的 函 数 rt_mb_send_wait()。 3.接 收 邮 件 线 程 接 收 邮 件 的 函 数 接 口 如 下 ,线 程 接 收 邮 件 时 ,需 要 指 定 接 收 邮 件 的 邮 箱 句 柄 、 邮 件 存 放 位 置 以 及 等 待 的 超 时 时 间 。 rt_err_t rt_mb_recv (rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) 参 数 mb 为 邮 箱 的 句 柄 ;value 为 邮 箱 消 息 存 储 地 址 ;timeout 为 等 待 超 时 时 间 。 接 收 成 功 ,则 返 回 RT_EOK;接 收 超 时 ,则 返 回 -RT_ETIMEOUT;接 收 失 败 , 返 回 -RT_ERROR。 只 有 当 邮 箱 中 有 邮 件 时 ,接 收 者 才 能 立 即 取 到 邮 件 并 返 回 RT_EOK; 否 则 接 收 线 程 会 根 据 设 定 的 超 时 时 间 ,挂 起 在 等 待 线 程 队 列 或 者 立 即 返 回 ( 超 时 时 间 设 定 为 0) 。 实 战 演 练 举 例 来 说 明 邮 箱 操 作 函 数 的 用 法 , 代 码 如 下 。 动 态 创 建 两 个 线 程 , 一 个 线 程 往 邮 箱 中 发 送 邮 件 , 一 个 线 程 从 邮 箱 中 收 取 邮 件 。 #include #define THREAD_PRIORITY 8 #define THREAD_TIMESLICE 5 /* 邮 箱 控 制 块 */ rt_mailbox_t mb_handle; static char mb_str1[] = "I'm a mail!"; static char mb_str2[] = "this is another mail!"; static char mb_str3[] = "over"; /* 线程 1 入口 */ static void thread1_entry(void *parameter) { char *str; while (1) { rt_kprintf("thread1: try to recv a mail\n"); /* 从邮箱中收取邮件 */ if (rt_mb_recv(mb_handle, (rt_ubase_t *)&str, RT_WAITING_FOREVER) == RT_EOK) { rt_kprintf("thread1: get a mail from mailbox, the content:%s\n", str); if (str == mb_str3) { break; } /* 延时 100ms */ rt_thread_mdelay(100); } } } /* 线程 2 入口 */ static void thread2_entry(void *parameter) { rt_uint8_t count = 0; while (count < 10) { count ++; if (count & 0x1) { /* 发送 mb_str1 地址到邮箱中 */ rt_mb_send(mb_handle, (rt_uint32_t)&mb_str1); } else { /* 发送 mb_str2 地址到邮箱中 */ rt_mb_send(mb_handle, (rt_uint32_t)&mb_str2); } /* 延 时 200ms */ rt_thread_mdelay(200); } /* 发送邮件告诉线程 1, 线程 2 已经运行结束 */ rt_mb_send(mb_handle, (rt_uint32_t)&mb_str3); } int main() { /* 线程控制块指针 */ rt_thread_t thread1 = RT_NULL; rt_thread_t thread2 = RT_NULL; /* 创建一个邮箱 */ mb_handle = rt_mb_create("mt", 32, RT_IPC_FLAG_FIFO); if (mb_handle == RT_NULL) { rt_kprintf("create mailbox failed.\n"); return -1; } /* 动态创建线程 1 */ thread1 = rt_thread_create("thread1", thread1_entry, RT_NULL, 1024, THREAD_PRIORITY - 1, THREAD_TIMESLICE); if(thread1 != RT_NULL) { /* 启动线程 */ rt_thread_startup(thread1); } /* 动态创建线程 2 */ thread2 = rt_thread_create("thread2", thread2_entry, RT_NULL, 1024, THREAD_PRIORITY, THREAD_TIMESLICE); if(thread2 != RT_NULL) { /* 启动线程 */ rt_thread_startup(thread2); } } 编 译 , 运 行 结 果 如 下 : 该 例 程 中 , 线 程 2 发 送 邮 件 , 共 发 送 了 11 次 ; 线 程 1 接 收 邮 件 ,接 收 到 了 11 封 邮 件 ,并 将 邮 件 内 容 打 印 出 来 ,并 根 据 判 断 结 束 运 行 。 其 他 操 作 函 数 对 于 RT-Thread 邮 箱 操 作 来 说 , 还 有 删 除 邮 箱 的 函 数 没 有 介 绍 。 可 以 简 单 了 解 一 下 。 1. 删 除 动 态 创 建 的 邮 箱

部分文件列表

文件名 大小
RT-Thread快速入门-消息邮箱.pdf 297K

全部评论(0)

暂无评论

上传资源 上传优质资源有赏金

  • 打赏
  • 30日榜单

推荐下载