RT_Thread内核机制学习(四)队列

news2024/11/26 13:33:31

队列

队列中每个消息块都有一个头部,指向下一个消息块。
在这里插入图片描述
消息块的内存是连在一起的,但是是用链表组织的。

struct rt_messagequeue
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */

    void                *msg_pool;                      /**< start address of message queue */

    rt_uint16_t          msg_size;                      /**< message size of each message */
    rt_uint16_t          max_msgs;                      /**< max number of messages */

    rt_uint16_t          entry;                         /**< index of messages in the queue */

    void                *msg_queue_head;                /**< list head */
    void                *msg_queue_tail;                /**< list tail */
    void                *msg_queue_free;                /**< pointer indicated the free node of queue */

    rt_list_t            suspend_sender_thread;         /**< sender thread suspended on this message queue */
};

共有三个指针,free指向空闲消息链表头部,head指向有数据的第一个消息块,tail指向有消息的最后一个消息块。

创建一个队列,用于线程A、B之间的通信。
队列最多含有5个消息,刚创建时这5个消息都是空的,都放在空闲链表里。
在这里插入图片描述
线程A向队列写入一个本地变量x:从队列的空闲链表中取出一个消息块,把x的值拷贝进去,这时队列中只有一个消息,所以队列的头部、尾部都指向这个消息。

在这里插入图片描述
线程A修改本地变量x为20,并把它写入队列:
从队列的空闲消息链表中取出一个消息,把x的值拷贝进去,放到队列的尾部。
在这里插入图片描述
头指针指向最先写入的消息块,尾写入最后写入的消息块。
在这里插入图片描述
线程B读队列,得到的数据放到本地变量y中,这个数据来自队列头部,链头指针指向下一个。
线程B读出消息后:原来的消息块变为空闲消息块,被放入队列的空闲链表msg_queue_free;

rt_mq_t rt_mq_create(const char *name,
                     rt_size_t   msg_size,
                     rt_size_t   max_msgs,
                     rt_uint8_t  flag)
{
    struct rt_messagequeue *mq;
    struct rt_mq_message *head;
    register rt_base_t temp;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* allocate object */
    mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name);//分配一个消息队列结构体
    if (mq == RT_NULL)
        return mq;

    /* set parent */
    mq->parent.parent.flag = flag;

    /* initialize ipc object */
    rt_ipc_object_init(&(mq->parent));

    /* initialize message queue */

    /* get correct message size */
    mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); //每个消息的size需要对齐
    mq->max_msgs = max_msgs;

    /* allocate message pool */
    mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs); //(每个消息的大小+每个消息结构体的大小)*最大消息数,这是一块连续的内存区域。分配出来的所有消息空间保存在msg_pool中。
    if (mq->msg_pool == RT_NULL)
    {
        rt_object_delete(&(mq->parent.parent));

        return RT_NULL;
    }

    /* initialize message list */
    mq->msg_queue_head = RT_NULL;//头指针和尾指针初始化为空
    mq->msg_queue_tail = RT_NULL;

    /* initialize message empty list */
    mq->msg_queue_free = RT_NULL;
    for (temp = 0; temp < mq->max_msgs; temp ++) //遍历每一个消息块
    {
        head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool +
                                        temp * (mq->msg_size + sizeof(struct rt_mq_message)));
        head->next = (struct rt_mq_message *)mq->msg_queue_free;
        mq->msg_queue_free = head;
    }

    /* the initial entry is zero */
    mq->entry = 0;

    /* initialize an additional list of sender suspend thread */
    rt_list_init(&(mq->suspend_sender_thread));

    return mq;
}
RTM_EXPORT(rt_mq_create);

struct rt_mq_message
{
    struct rt_mq_message *next;
};//消息结构体

发送消息

/* get a free list, there must be an empty item */
    msg = (struct rt_mq_message *)mq->msg_queue_free; //从free链表获取一个消息块

//取出消息块后,free链表指针指向消息块的下一个
mq->msg_queue_free = msg->next;

//将buffer数据拷贝进去
rt_memcpy(msg + 1, buffer, size);

//尾部指针指向此消息
mq->msg_queue_tail = msg;

//如果头部指针为空,代表第一次存放数据进去,因此头部指针也指向此消息。下一次,消息不为空时,再放消息,头部不变。
if (mq->msg_queue_head == RT_NULL)
        mq->msg_queue_head = msg;

读入消息

//新的空闲消息块,直接让空闲链表头部指向它,插入表头
msg->next = (struct rt_mq_message *)mq->msg_queue_free;
mq->msg_queue_free = msg;

写消息时的互斥操作

 /* disable interrupt */
    temp = rt_hw_interrupt_disable();//在取出消息块,写消息之前关中断,其它线程无法打扰。

互斥用关中断来实现。
互斥量也是用关中断实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/952946.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《独立开发者首次飞行指南》终于来了!!

大家好&#xff0c;我是彭涛。 现在&#xff0c;每年都有各家大厂裁员&#xff0c;各类中小厂跑路&#xff0c;失业人数越来越多的新闻。如果&#xff0c;我们身背房贷&#xff0c;我们应该都会非常焦虑。大环境下&#xff0c;我们不得不逐一探索新的赚钱之道&#xff0c;前段时…

anaconda环境迁移

conda环境迁移第一步 进入anaconda安装文件夹&#xff0c;然后进入envs文件夹&#xff0c;下面的每一个文件夹都是你创建的环境&#xff0c; 准备一个u盘之类的&#xff0c;把整个文件夹复制下来&#xff0c;然后打开另外一台机器&#xff0c;把同样的文件夹复制到同样的文件夹…

JS设置视频播放速度

方法 一&#xff1a;示例代码 document.querySelector(video).playbackRate 5; 进入到要加速的视频页面按F12打开控制控制台输入代码并回车 方法二&#xff1a;示例代码 document.getElementsByTagName("video")[0].playbackRate 5; 进入到要加速的视频页面按F…

钉钉消息已读、未读咋实现的嘞?

前言 一款app&#xff0c;消息页面有&#xff1a;钱包通知、最近访客等各种通知类别&#xff0c;每个类别可能有新的通知消息&#xff0c;实现已读、未读功能&#xff0c;包括多少个未读&#xff0c;这个是怎么实现的呢&#xff1f;比如用户A访问了用户B的主页&#xff0c;难道…

Java实现获取微信小程序scheme码报错

如标题所见&#xff0c;使用Java获取小程序scheme时除了出现文档中的常见错误&#xff0c;我将我调试的时候遇到的错误和解决方式分享出来方便大家少花一部分时间解决该问题。&#xff08;往下划有结论节省时间&#xff09;。 获取scheme码之前需要先获取access_token&#xff…

Vue生命周期(详细)

生命周期 图&#xff1a; 可以理解vue生命周期就是指vue实例从创建到销毁的过程&#xff0c;在vue中分为8个阶段&#xff1a;创建前/后&#xff0c;载入前/后&#xff0c;更新前/后&#xff0c;销毁前/后。 一、创建&#xff08;实例&#xff09; 1、beforeCreate&#xff1a…

问道管理:市盈率怎么计算?

市盈率是衡量一家公司股票价格是否合理的重要目标之一&#xff0c;核算市盈率的公式是将一家公司的股票价格除以每股收益&#xff0c;也便是市盈率 股票价格 每股收益。市盈率能够告诉你一个公司的股票价格是否高估或轻视&#xff0c;是投资者在买入或卖出一家公司股票时需求…

拒绝摆烂!C语言练习打卡第七天

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;每日一练 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、选择题 &#x1f4dd;1.第一题 &#x1f4dd;2.第二题 &#x1f4d…

UE5.1 透明渲染流程框架图

相关文章&#xff1a; UE 透明物体绘制准备_sh15285118586的博客-CSDN博客 透明直接光和间接光生成_sh15285118586的博客-CSDN博客 Scene:Translucency-Translucency(AfterDOF)_sh15285118586的博客-CSDN博客 Scene:Translucency-Distortion &PostProcessing:ComposeTran…

系列十四、Chrome浏览器安装JSONView插件

一、下载JSONView插件 说明&#xff1a;如果能够上外网的话&#xff0c;在Chrome应用商店下载JSON格式化插件安装即可 我分享的链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1H8VUH8e9Tw7JqrlJEBnQQg?pwdyyds 提取码&#xff1a;yyds 二、安装 解压》Chrome…

MybatisPlus-Generator

文章目录 一、前言二、MybatisPlus代码生成器1、引入依赖2、编写生成代码3、配置说明3.1、全局配置(GlobalConfig)3.2、包配置(PackageConfig)3.3、模板配置(TemplateConfig)3.4、策略配置(StrategyConfig)3.4.1、Entity 策略配置3.4.2、Controller 策略配置3.4.3、Service 策略…

IDEA快速设置全局JDK

出bug 了 JDK 不识别了&#xff0c;才想起来要设置jdk &#xff0c;现在一般查到的都是setting 设置全局的idea设置。但是老玩家的我怎么会不知道有一个设置全局jdk 的一个设置 setings 设置是对idea 的基础设置。 但是还有一个隐藏页面快捷键【CtrlAltShiftS】 接下来自己研究…

B080-RabbitMQ

目录 RabbitMQ认识概念使用场景优点AMQP协议JMS RabbitMQ安装安装elang安装RabbitMQ安装管理插件登录RabbitMQ消息队列的工作流程 RabbitMQ常用模型HelloWorld-基本消息模型生产者发送消息导包获取链接工具类消息的生产者 消费者消费消息模拟消费者手动签收消息 Work QueuesSen…

docker启动paddlespeech服务,并使用接口调用

一、检查docker容器是否启动 1.输入命令 systemctl status docker 启动 systemctl start docker 守护进程重启 sudo systemctl daemon-reload 重启docker服务 systemctl restart docker 重启docker服务 sudo service docker restart 关闭docker service docker…

【Nacos】使用Nacos进行服务发现、配置管理

Nacos Nacos是 Dynamic Naming and Configuration Service 的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 版本说明&#xff1a;版本说明 alibaba/spring-cloud-alibaba Wiki GitHub <properties><java.version>…

21 Linux高级篇-日志管理

21 Linux高级篇-日志管理 文章目录 21 Linux高级篇-日志管理21.1 系统常用的日志21.2 日志管理服务rsyslogd21.2.1 *日志记录原理21.2.2 配置文件/etc/rsyslog.conf21.2.3 日志文件格式 21.3 日志轮替21.3.1 配置文件/etc/logrotate.conf & /etc/logrotate.d/21.3.2 可执行…

memcpy 函数

目录 函数介绍&#xff1a; 函数解析&#xff1a; memcpy函数复制的数据长度 内存重叠 凑不出元素的字节数 模拟memcpy 函数介绍&#xff1a; memcpy函数是一个用于内存复制的函数&#xff0c;声明在 string.h 中&#xff08;C是 cstring&#xff09;。 其原型是&…

Excel操作技巧:如何粘贴保留单元格大小

有时我们需要在Excel中复制和粘贴并保持单元格大小。它在工作中节省了很多时间。也使数据集更具吸引力。在这篇文章中,我们将通过一些简单快捷的示例和解释来学习如何做到这一点。 一、使用上下文菜单在Excel中复制和粘贴以保持单元格大小 上下文菜单是Excel的一个重要功能。…

Openlayers 叠加天地图-中国近海海洋等深面图层服务

Openlayers 叠加天地图-中国近海海洋等深面图层服务 核心代码完整代码&#xff1a;在线示例 偶然发现天地图有一个近海海洋图层&#xff0c;觉得不错&#xff0c;于是尝试叠加一下&#xff0c;花费了一些时间&#xff0c;叠加成功&#xff0c;这里分享一下。 本文包括核心代码…