前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >zephyr笔记 2.5.4 消息队列

zephyr笔记 2.5.4 消息队列

作者头像
twowinter
发布2020-04-17 18:17:00
8890
发布2020-04-17 18:17:00
举报
文章被收录于专栏:twowintertwowinter

1 前言

消息队列是实现简单消息队列的内核对象,允许线程和ISR异步发送和接收固定大小的数据项。

我正在学习 Zephyr,一个很可能会用到很多物联网设备上的操作系统,如果你也感兴趣,可点此查看帖子zephyr学习笔记汇总

2 概念

可以定义任何数量的消息队列。 每个消息队列都由其内存地址引用。

消息队列具有以下关键属性:

  • 已发送但尚未收到的数据项的环形缓冲区。
  • 数据项大小,以字节为单位。
  • 可以在环形缓冲区中排队的最大数量的数据项。

消息队列的环形缓冲区必须与N字节边界对齐,其中N是2的幂(即1,2,4,8,…)。为确保存储在环形缓冲区中的消息与此边界相似,数据项大小必须也是N的倍数。

消息队列在被使用之前必须被初始化。这将其环形缓冲区设置为空。

数据项可以由线程或ISR发送到消息队列。发送线程指向的数据项被复制到一个等待线程(如果存在的话);否则如果空间可用,则将项目复制到消息队列的环形缓冲区中。在任何一种情况下,发送的数据区域的大小必须等于消息队列的数据项大小。

如果线程在环形缓冲区已满时尝试发送数据项,发送线程可能会选择等待空间变为可用。当环形缓冲区已满时,任意数量的发送线程可能会同时等待;当空间变得可用时,它被赋予等待时间最长的最高优先级发送线程。

数据项可以由线程从消息队列接收。数据项被复制到接收线程指定的区域;接收区域的大小必须等于消息队列的数据项大小。

如果线程尝试在环形缓冲区为空时接收数据项,接收线程可能会选择等待发送数据项。当环形缓冲区为空时,任意数量的接收线程可能会同时等待;当数据项变得可用时,它被赋予等待时间最长的最高优先级接收线程。

代码语言:javascript
复制
注意:内核确实允许ISR从消息队列接收项目,但是如果消息队列为空,则ISR不能尝试等待。

3 操作

3.1 定义一个消息队列

消息队列使用 struct k_msgq 类型的变量来定义。它必须通过调用k_msgq_init() 来初始化。

以下代码定义并初始化一个空的消息队列,该消息队列能够保存10个项目,每个项目的长度为12个字节。

代码语言:javascript
复制
struct data_item_type {
    u32_t field1;
    u32_t field2;
    u32_t field3;
};

char __aligned(4) my_msgq_buffer[10 * sizeof(data_item_type)];
struct k_msgq my_msgq;

k_msgq_init(&my_msgq, my_msgq_buffer, sizeof(data_item_type), 10);

或者,可以通过调用 K_MSGQ_DEFINE 在编译时定义和初始化消息队列。

以下代码与上面的代码段具有相同的效果。观察宏定义了消息队列及其缓冲区。

代码语言:javascript
复制
K_MSGQ_DEFINE(my_msgq, sizeof(data_item_type), 10, 4);

3.2 写入消息队列

通过调用 k_msgq_put() 将数据项添加到消息队列中。

以下代码构建在上述示例上,并使用消息队列将数据项从生成线程传递到一个或多个消费线程。 如果消息队列由于消费者无法跟上而填满,则生成线程会抛弃所有现有数据,以便保存新数据。

代码语言:javascript
复制
void producer_thread(void)
{
    struct data_item_t data;

    while (1) {
        /* create data item to send (e.g. measurement, timestamp, ...) */
        data = ...

        /* send data to consumers */
        while (k_msgq_put(&my_msgq, &data, K_NO_WAIT) != 0) {
            /* message queue is full: purge old data & try again */
            k_msgq_purge(&my_msgq);
        }

        /* data item was successfully added to message queue */
    }
}

3.3 从消息队列中读取

通过调用 k_msgq_get() 从数据队列中获取数据项。

以下代码构建在上述示例上,并使用消息队列处理由一个或多个生成线程生成的数据项。

代码语言:javascript
复制
void consumer_thread(void)
{
    struct data_item_t data;

    while (1) {
        /* get a data item */
        k_msgq_get(&my_msgq, &data, K_FOREVER);

        /* process data item */
        ...
    }
}

4 建议用法

使用消息队列以异步方式在线程之间传输小数据项。

代码语言:javascript
复制
如果需要,可以使用消息队列来传输大数据项。但是,这会增加中断延迟,因为在写入或读取数据项时中断被锁定。 通常通过交换指向数据项的指针而不是数据项本身来传送大数据项。内核的内存映射和内存池对象类型可以有助于此类数据传输。

通过使用内核的邮箱对象类型可以实现同步传输。

5 配置选项

6 APIs

下列消息队列API,都在 kernel.h 中提供了:

代码语言:javascript
复制
K_MSGQ_DEFINE
k_msgq_init()
k_msgq_put()
k_msgq_get()
k_msgq_purge()
k_msgq_num_used_get()
k_msgq_num_free_get()
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 前言
  • 2 概念
  • 3 操作
    • 3.1 定义一个消息队列
      • 3.2 写入消息队列
        • 3.3 从消息队列中读取
        • 4 建议用法
        • 5 配置选项
        • 6 APIs
        相关产品与服务
        消息队列 CMQ 版
        消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档