资料介绍
上 一 篇 介 绍 了 消 息 邮 箱 , 本 篇 文 章 介 绍 线 程 ( 任 务 ) 间 通 信 的 另 一
种 方 式 ——消 息 队 列 。
消 息 队 列 在 实 际 项 目 中 应 用 较 多 , 建 议 初 学 者 应 该 熟 练 掌 握 。
掌 握 了 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)