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

RT-Thread快速入门-消息队列

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

资料介绍

上 一 篇 介 绍 了 消 息 邮 箱 , 本 篇 文 章 介 绍 线 程 ( 任 务 ) 间 通 信 的 另 一 种 方 式 ——消 息 队 列 。 消 息 队 列 在 实 际 项 目 中 应 用 较 多 , 建 议 初 学 者 应 该 熟 练 掌 握 。 掌 握 了 RT-Thread 消 息 队 列 的 原 理 和 操 作 方 法 , 如 果 再 学 习 其 他 款 RTOS, 会 感 觉 很 轻 松 。 消 息 队 列 的 工 作 机 制 1. 理 解 消 息 队 列 线 程 或 中 断 服 务 例 程 可 以 将 一 条 或 多 条 消 息 放 入 消 息 队 列 中 。 一 个 或 多 个 线 程 也 可 以 从 消 息 队 列 中 获 得 消 息 。 当 有 多 个 消 息 发 送 到 消 息 队 列 时 , 通 常 将 先 进 入 消 息 队 列 的 消 息 先 传 给 线 程 , 也 就 是 说 , 线 程 先 得 到 的 是 最 先 进 入 消 息 队 列 的 消 息 , 即 先 进 先 出 原 则 (FIFO)。 如 下 图 所 示 2. 消 息 队 列 控 制 块 消 息 队 列 控 制 块 是 RT-Thread 系 统 管 理 消 息 队 列 的 一 种 数 据 结 构 , 由 结 构 体 struc t rt_mes sagequeue 表 示 。另 外 rt_mq_t 表 示 消 息 队 列 的 句 柄 , 即 指 向 消 息 队 列 控 制 块 的 指 针 。 消 息 队 列 控 制 块 的 数 据 结 构 定 义 如 下 : struct rt_messagequeue { struct rt_ipc_object parent; /* 继承自 ipc_object 类 */ void *msg_pool; /* 指向存放消息的缓冲区的指 针 */ rt_uint16_t msg_size; /* 每个消息的长度 */ rt_uint16_t max_msgs; /* 消息队列最大能容纳的消息 数 */ rt_uint16_t entry; /* 消息队列中已有的消息数 */ void *msg_queue_head; /* 消息链表头 */ void *msg_queue_tail; /* 消息链表尾 */ void *msg_queue_free; /* 空闲消息链表 */ rt_list_t suspend_sender_thread; /* 发送线程的挂起等待队 列 */ }; typedef struct rt_messagequeue *rt_mq_t; 结 构 体 定 义 中 ,继 承 关 系 一 目 了 然 ,不 再 赘 述 。rt_mes sagequeue 对 象 从 rt_ipc_object 中 派 生 , 由 IPC 容 器 所 管 理 。 消 息 队 列 的 操 作 函 数 RT-Thread 提 供 了 多 种 管 理 消 息 队 列 的 接 口 函 数 。包 括 :创 建 消 息 队 列 - 发 送 消 息 - 接 收 消 息 - 删 除 消 息 队 列 。 如 下 图 所 示 : 对 于 初 学 者 来 说 , 掌 握 其 中 常 用 的 函 数 即 可 。 本 文 重 点 介 绍 消 息 队 列 常 用 的 函 数 接 口 。 实 际 项 目 中 ,使 用 消 息 队 列 的 流 程 为 :创 建 消 息 队 列 - 发 送 消 息 - 接 收 消 息 。 我 们 就 重 点 介 绍 一 下 对 应 的 操 作 函 数 。 1. 创 建 消 息 队 列 在 RT-Thread 中 , 同 其 他 内 核 对 象 一 样 。 创 建 消 息 队 列 也 有 两 种 方 式 : ( 1) 动 态 创 建 ( 2) 静 态 初 始 化 。 动 态 创 建 一 个 消 息 队 列 的 函 数 接 口 如 下 , 调 用 此 函 数 时 , 内 核 动 态 创 建 一 个 消 息 队 列 控 制 块 。 然 后 再 分 配 一 块 内 存 空 间 , 用 于 存 放 消 息 ,这 块 内 存 的 大 小 为 :消 息 队 列 个 数 * [消 息 大 小 + 消 息 头 大 小 ]。 最 后 初 始 化 消 息 队 列 以 及 消 息 队 列 控 制 块 。 rt_mq_t rt_mq_create(const char *name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag) 参 数 name 为 消 息 队 列 名 称 ; msg_s ize 为 队 列 中 一 条 消 息 的 长 度 , 单 位 为 字 节 ;max_msgs 为 消 息 队 列 的 最 大 个 数 ;flag 为 消 息 队 列 的 等 待 方 式 。 创 建 成 功 , 返 回 消 息 队 列 的 句 柄 ; 创 建 失 败 , 则 返 回 RT_NULL。 静 态 方 式 创 建 消 息 队 列 需 要 两 步 :  定 义 一 个 消 息 队 列 控 制 块 以 及 一 段 存 放 消 息 的 缓 冲 区   初 始 化 消 息 队 列 控 制 块  消 息 队 列 控 制 块 初 始 化 函 数 如 下 : rt_err_t rt_mq_init(rt_mq_t mq, const char* name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag); 函 数 的 参 数 解 释 如 下 表 : 参 数 描 述 mq 消 息 队 列 控 制 块 的 指 针 name 消 息 队 列 的 名 称 msgpool 存 放 消 息 的 缓 冲 的 指 针 msg_size 一 条 消 息 的 最 大 长 度 , 单 位 为 字 节 pool_size 存 放 消 息 的 缓 冲 区 大 小 flag 创 建 消 息 队 列 标 志 初 始 化 消 息 队 列 函 数 返 回 RT_EOK。 创 建 或 初 始 化 完 成 消 息 队 列 后 ,所 有 消 息 块 都 挂 在 空 闲 消 息 链 表 上 , 消 息 队 列 为 空 。 创 建 消 息 队 列 的 标 志 变 量 取 值 有 两 种 :  RT_IPC_FLAG_FIFO, 等 待 消 息 队 列 的 线 程 按 照 先 进 先 出 的 方 式 进 行 排 列 。   RT_IPC_FLAG_PRIO,等 待 消 息 队 列 的 线 程 按 照 优 先 级 的 方 式 进 行 排 列 。  2. 发 送 消 息 RT-Thread 提 供 的 发 送 消 息 接 口 函 数 有 两 种 :一 种 是 无 等 待 超 时 接 口 , 一 种 是 有 等 待 超 时 。 线 程 或 者 中 断 服 务 程 序 都 可 以 给 消 息 队 列 发 送 消 息 , 发 送 消 息 的 函 数 接 口 如 下 , 此 函 数 没 有 等 待 超 时 参 数 。 rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size) 参 数 mq 为 消 息 队 列 对 象 的 句 柄 ; buffer 为 存 放 消 息 缓 冲 区 的 指 针 ; size 为 消 息 大 小 。 发 送 成 功 , 函 数 返 回 RT_EOK; 消 息 队 列 已 满 , 返 回 -RT_EFULL; 发 送 的 消 息 长 度 大 于 消 息 队 列 中 消 息 块 的 最 大 长 度 , 则 返 回 -RT_ERROR。 等 待 方 式 发 送 消 息 的 函 数 接 口 如 下 , 这 个 函 数 有 等 待 超 时 参 数 : rt_err_t rt_mq_send_wait(rt_mq_t mq, const void *buffer, rt_size_t size, rt_int32_t timeout) 此 函 数 的 参 数 timeout 为 发 送 等 待 超 时 时 间 , 单 位 为 系 统 时 钟 节 拍 。 其 他 参 数 与 rt_mq_send() 相 同 。 如 果 消 息 队 列 已 经 满 了 ,发 送 线 程 会 根 据 设 定 的 timeout 参 数 等 待 消 息 队 列 中 因 为 收 取 消 息 而 空 出 空 间 。 若 超 时 时 间 到 达 依 然 没 有 空 出 空 间 , 则 发 送 线 程 将 会 被 唤 醒 并 返 回 错 误 码 。 返 回 RT_EOK 表 示 发 送 成 功 ; 返 回 -RT_ETIMEOUT 表 示 超 时 ; 返 回 -RT_ERROR 表 示 发 送 失 败 。 注 意 : 在 中 断 服 务 例 程 中 发 送 邮 件 时 , 应 该 采 用 无 等 待 延 时 的 方 式 发 送 , 直 接 使 用 rt_mq_send() 或 者 等 待 超 时 设 定 为 0 的 函 数 rt_mq_send_wait()。 3. 接 收 消 息 线 程 接 收 消 息 的 函 数 接 口 如 下 , rt_err_t rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, rt_int32_t timeout) 参 数 mq 为 消 息 队 列 对 象 的 句 柄 ;buffer 为 消 息 内 容 ;size 为 消 息 大 小 ; timeout 为 超 时 时 间 。 接 收 消 息 时 , 需 要 指 定 消 息 队 列 的 句 柄 , 以 及 一 块 用 于 存 储 消 息 的 缓 冲 区 , 接 收 到 的 消 息 内 容 将 被 复 制 到 该 缓 冲 区 里 。 还 需 指 定 等 待 消 息 的 超 时 时 间 。 当 消 息 队 列 中 为 空 时 , 接 收 消 息 的 线 程 会 根 据 设 定 的 超 时 时 间 , 挂 起 在 消 息 队 列 的 等 待 线 程 队 列 上 , 或 直 接 返 回 。 实 战 演 练 多 说 无 益 , 实 践 出 真 知 。 我 们 来 举 个 例 子 , 学 习 一 下 如 何 使 用 消 息 队 列 。 动 态 创 建 两 个 线 程 和 一 个 消 息 队 列 , 一 个 线 程 往 消 息 队 列 中 发 送 消 息 , 一 个 线 程 从 消 息 队 列 中 接 收 消 息 。 代 码 如 下 : #include #define THREAD_PRIORITY 8 #define THREAD_TIMESLICE 5 /* 消息队列句柄 */ rt_mq_t mq_handle; /* 线程 1 入口 */ static void thread1_entry(void *parameter) { char buf = 0; rt_uint8_t cnt = 0; while (1) { /* 从消息队列中收取消息 */ if (rt_mq_recv(mq_handle, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK) { rt_kprintf("thread1: recv msg , the content: %c\n", buf); if (cnt == 19) { break; } cnt++; } rt_thread_mdelay(1); } } /* 线程 2 入口 */ static void thread2_entry(void *parameter) { int result; char buf = 'A'; rt_uint8_t cnt = 0; while (1) { rt_kprintf("thread2: send message - %c\n", buf); /* 向消息队列发送消息 */ result = rt_mq_send(mq_handle, &buf, 1); if(result != RT_EOK) { rt_kprintf("rt_mq_send ERR\n"); } buf++; cnt++; if(cnt >= 20) { rt_kprintf("message queue stop send, thread2 quit\n"); break; } /* 延时 50ms */ rt_thread_mdelay(500); } } int main() { /* 线程控制块指针 */ rt_thread_t thread1 = RT_NULL; rt_thread_t thread2 = RT_NULL; /* 创建一个邮箱 */ mq_handle = rt_mq_create("mq", 1, 2048, RT_IPC_FLAG_FIFO); if (mq_handle == RT_NULL) { rt_kprintf("create msg queue 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); } } 编 译 执 行 结 果 如 下 该 例 程 演 示 了 消 息 队 列 如 何 使 用 。线 程 1 从 消 息 队 列 中 收 取 消 息 ; 线 程 2 定 时 给 消 息 队 列 发 送 消 息 , 一 共 发 送 了 20 条 消 息 。 ### 其 他 操 作 函 数 对 于 RT-Thread 消 息 队 列 操 作 来 说 , 还 有 几 个 函 数 没 有 介 绍 。 可 以 简 单 了 解 一 下 。 1. 删 除 动 态 创 建 的 消 息 队 列 删 除 由 rt_mq_create() 函 数 创 建 的 消 息 队 列 , 可 以 调 用 如 下 函 数 : rt_err_t rt_mq_delete(rt_mq_t mq) 调 用 此 函 数 , 可 以 释 放 消 息 队 列 控 制 块 占 用 的 内 存 资 源 以 及 消 息 缓 冲 区 占 用 的 内 存 。 在 删 除 一 个 消 息 队 列 对 象 时 , 应 该 确 保 该 消 息 队 列 不 再 被 使 用 。 在 删 除 前 会 唤 醒 所 有 挂 起 在 该 消 息 队 列 上 的 线 程 , 然 后 释 放 消 息 队 列 对 象 占 用 的 内 存 块 。 2. 脱 离 静 态 创 建 的 消 息 队 列 删 除 rt_mq_init() 初 始 化 的 消 息 队 列 , 可 以 用 如 下 函 数 : rt_err_t rt_mq_detach(rt_mq_t mq) 调 用 此 函 数 时 , 首 先 会 唤 醒 所 有 挂 起 在 该 消 息 队 列 中 , 线 程 等 待 队 列 上 的 线 程 , 然 后 将 该 消 息 队 列 从 内 核 对 象 管 理 器 中 脱 离 。 3.发 送 紧 急 消 息 RT-Thread 中 ,提 供 了 一 种 发 送 紧 急 消 息 的 函 数 接 口 ,其 过 程 与 发 送 消 息 几 乎 一 样 。 其 函 数 接 口 如 下 : rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size); 在 发 送 紧 急 消 息 时 , 从 空 闲 消 息 链 表 上 取 下 来 的 消 息 块 不 是 挂 到 消 息 队 列 的 队 尾 , 而 是 挂 到 队 首 , 这 样 , 接 收 者 就 能 够 优 先 接 收 到 紧 急 消 息 , 从 而 及 时 进 行 消 息 处 理 。

部分文件列表

文件名 大小
RT-Thread快速入门-消息队列.pdf 275K

全部评论(0)

暂无评论